How would I get just the current working directory name in a bash script, or even better, just a terminal command.
pwd
gives the full path of the current working directory, e.g. /opt/local/bin
but I only want bin
No need for basename, and especially no need for a subshell running pwd (which adds an extra, and expensive, fork operation); the shell can do this internally using parameter expansion:
result=${PWD##*/} # to assign to a variable
result=${result:-/} # to correct for the case where PWD=/
printf '%s\n' "${PWD##*/}" # to print to stdout
# ...more robust than echo for unusual names
# (consider a directory named -e or -n)
printf '%q\n' "${PWD##*/}" # to print to stdout, quoted for use as shell input
# ...useful to make hidden characters readable.
Note that if you're applying this technique in other circumstances (not PWD
, but some other variable holding a directory name), you might need to trim any trailing slashes. The below uses bash's extglob support to work even with multiple trailing slashes:
dirname=/path/to/somewhere//
shopt -s extglob # enable +(...) glob syntax
result=${dirname%%+(/)} # trim however many trailing slashes exist
result=${result##*/} # remove everything before the last / that still remains
result=${result:-/} # correct for dirname=/ case
printf '%s\n' "$result"
Alternatively, without extglob
:
dirname="/path/to/somewhere//"
result="${dirname%"${dirname##*[!/]}"}" # extglob-free multi-trailing-/ trim
result="${result##*/}" # remove everything before the last /
result=${result:-/} # correct for dirname=/ case
Use the basename
program. For your case:
% basename "$PWD"
bin
basename
program? What is wrong with this answer besides missing the quotes?
basename
is indeed an external program that does the right thing, but running any external program for a thing bash can do out-of-the-box using only built-in functionality is silly, incurring performance impact (fork()
, execve()
, wait()
, etc) for no reason.
basename
here don't apply to dirname
, because dirname
has functionality that ${PWD##*/}
does not -- transforming a string with no slashes to .
, for instance. Thus, while using dirname
as an external tool has performance overhead, it also has functionality that helps to compensate for same.
basename
is less "efficient". But it's probably more efficient in terms of developer productivity because it's easy to remember compared to the ugly bash syntax. So if you remember it, go for it. Otherwise, basename
works just as well. Has anyone ever had to improve the "performance" of a bash script and make it more efficient?
$ echo "${PWD##*/}"
echo "${PWD##*/}"
.
name=${PWD##*/}
would be right, and name=$(echo "${PWD##*/}")
would be wrong (in a needless-inefficiency sense).
Use:
basename "$PWD"
OR
IFS=/
var=($PWD)
echo ${var[-1]}
Turn the Internal Filename Separator (IFS) back to space.
IFS=
There is one space after the IFS.
You can use a combination of pwd and basename. E.g.
#!/bin/bash
CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`
echo "$BASENAME"
exit;
How about grep:
pwd | grep -o '[^/]*$'
pwd | xargs basename
doesn't.. probably not that important but the other answer is simpler and more consistent across environments
basename $(pwd)
or
echo "$(basename $(pwd))"
pwd
is string-split and glob-expanded before being passed to basename
.
basename "$(pwd)"
-- though that's very inefficient compared to just basename "$PWD"
, which is itself inefficient compared to using a parameter expansion instead of calling basename
at all.
This thread is great! Here is one more flavor:
pwd | awk -F / '{print $NF}'
I like the selected answer (Charles Duffy), but be careful if you are in a symlinked dir and you want the name of the target dir. Unfortunately I don't think it can be done in a single parameter expansion expression, perhaps I'm mistaken. This should work:
target_PWD=$(readlink -f .)
echo ${target_PWD##*/}
To see this, an experiment:
cd foo
ln -s . bar
echo ${PWD##*/}
reports "bar"
DIRNAME
To show the leading directories of a path (without incurring a fork-exec of /usr/bin/dirname):
echo ${target_PWD%/*}
This will e.g. transform foo/bar/baz -> foo/bar
readlink -f
is a GNU extension, and thus not available on the BSDs (including OS X).
echo "$PWD" | sed 's!.*/!!'
If you are using Bourne shell or ${PWD##*/}
is not available.
${PWD##*/}
is POSIX sh -- every modern /bin/sh (including dash, ash, etc) supports it; to hit actual Bourne on a recent box, you'd need to be on a mildly oldish Solaris system. Beyond that -- echo "$PWD"
; leaving out the quotes leads to bugs (if the directory name has spaces, wildcard characters, etc).
Surprisingly, no one mentioned this alternative that uses only built-in bash commands:
i="$IFS";IFS='/';set -f;p=($PWD);set +f;IFS="$i";echo "${p[-1]}"
As an added bonus you can easily obtain the name of the parent directory with:
[ "${#p[@]}" -gt 1 ] && echo "${p[-2]}"
These will work on Bash 4.3-alpha or newer.
There are a lots way of doing that I particularly liked Charles way because it avoid a new process, but before know this I solved it with awk
pwd | awk -F/ '{print $NF}'
For the find jockeys out there like me:
find $PWD -maxdepth 0 -printf "%f\n"
$PWD
to "$PWD"
to correctly handle unusual directory names.
i usually use this in sh scripts
SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
echo "Running from ${RUN_PATH}"
...
cd ${RUN_PATH}/subfolder
you can use this to automate things ...
readlink: illegal option -- f usage: readlink [-n] [file ...]
Just use:
pwd | xargs basename
or
basename "`pwd`"
xargs
formultion is inefficient and buggy when directory names contain literal newlines or quote characters, and the second formulation calls the pwd
command in a subshell, rather than retrieving the same result via a built-in variable expansion.
Below grep with regex is also working,
>pwd | grep -o "\w*-*$"
If you want to see only the current directory in the bash prompt region, you can edit .bashrc
file in ~
. Change \w
to \W
in the line:
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
Run source ~/.bashrc
and it will only display the directory name in the prompt region.
Ref: https://superuser.com/questions/60555/show-only-current-directory-name-not-full-path-on-bash-prompt
I strongly prefer using gbasename
, which is part of GNU coreutils.
basename
there. It's only typically called gbasename
on MacOS and other platforms that otherwise ship with a non-GNU basename.
You can use the basename utility which deletes any prefix ending in / and the suffix (if present in string) from string, and prints the result on the standard output.
$basename <path-of-directory>
The following commands will result in printing your current working directory in a bash script.
pushd .
CURRENT_DIR="`cd $1; pwd`"
popd
echo $CURRENT_DIR
$1
will contain the current working directory. (2) The pushd
and popd
serve no purpose here because anything inside backticks is done in a subshell -- so it can't affect the parent shell's directory to start with. (3) Using "$(cd "$1"; pwd)"
would be both more readable and resilient against directory names with whitespace.
Just remove any character until a /
(or \
, if you're on Windows). As the match is gonna be made greedy it will remove everything until the last /
:
pwd | sed 's/.*\///g'
In your case the result is as expected:
λ a='/opt/local/bin'
λ echo $a | sed 's/.*\///g'
bin
Success story sharing
$PWD
is the name of a built-in bash variable; all built-in variable names are in all-caps (to distinguish them from local variables, which should always have at least one lower-case character).result=${PWD#*/}
does not evaluate to/full/path/to/directory
; instead, it strips only the first element, making itpath/to/directory
; using two#
characters makes the pattern match greedy, matching as many characters as it can. Read the parameter expansion page, linked in the answer, for more.pwd
is not always the same as the value of$PWD
, due to complications arising fromcd
ing through symbolic links, whether bash has the-o physical
option set, and so on. This used to get especially nasty around handling of automounted directories, where recording the physical path instead of the logical one would produce a path that, if used, would allow the automounter to spontaneously dismount the directory one was using.sh
andcsh
and if you wanted the backspace key to work you had to read the wholestty
man page, and we liked it!"