How could I retrieve the current working directory/folder 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.
How could I retrieve the current working directory/folder 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 is / (root)
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
$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 it path/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 from cding 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 and csh and if you wanted the backspace key to work you had to read the whole stty man page, and we liked it!"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).You can use a combination of pwd and basename. E.g.
#!/bin/bash
CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`
echo "$BASENAME"
exit;
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.
nullglob or failglob options are enabled). I'd argue that invisible magic is the worst kind: because people don't know it's there, they don't know what the gotchas and corner cases are.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 environmentsbasename $(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.echo "${PWD##*/}" haha 😂 .Just run the following command line:
basename $(pwd)
If you want to copy that name:
basename $(pwd) | pbcopy
Or using xclip command if it is installed:
basename $(pwd) | xclip -selection clipboard
basename "$(pwd)"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"
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}'
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 ...
For the find jockeys out there like me:
find $PWD -maxdepth 0 -printf "%f\n"
$PWD to "$PWD" to correctly handle unusual directory names.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.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.