Suppose I have a file /from/here/to/there.txt
, and want to get only the last part of its dirname to
instead of /from/here/to
, what should I do?

- 39,467
- 16
- 112
- 140

- 1,342
- 2
- 9
- 7
9 Answers
You can use basename
even though it's not a file. Strip off the file name using dirname
, then use basename
to get the last element of the string:
dir="/from/here/to/there.txt"
dir="$(dirname $dir)" # Returns "/from/here/to"
dir="$(basename $dir)" # Returns just "to"
The opposite of dirname
is basename
:
basename "$(dirname "/from/here/to/there.txt")"

- 116,971
- 11
- 170
- 194
Using bash
string functions:
$ s="/from/here/to/there.txt"
$ s="${s%/*}" && echo "${s##*/}"
to

- 74,723
- 23
- 102
- 147
Using Bash parameter expansion, you could do this:
path="/from/here/to/there.txt"
dir="${path%/*}" # sets dir to '/from/here/to' (equivalent of dirname)
last_dir="${dir##*/}" # sets last_dir to 'to' (equivalent of basename)
This is more efficient since no external commands are used.

- 39,467
- 16
- 112
- 140
-
I just tested this. On FreeBSD here are my results: Code: #!/bin/sh cd /var/svn/repos path="$1" echo "${path}" dir="${path%/*}" echo "${dir}" actual="${dir##*/}" echo "${actual}" ---------------------------------------- Results: $ ./makerepo.sh /var/test /var/test /var var $ ------------------------------------ Fail! Sorry. Seemed a good method but not a correct answer. – Richard Robertson Nov 18 '17 at 16:04
Pure BASH way:
s="/from/here/to/there.txt"
[[ "$s" =~ ([^/]+)/[^/]+$ ]] && echo "${BASH_REMATCH[1]}"
to

- 761,203
- 64
- 569
- 643
-
2Will not work if file has no dot `.`. Will not work if directory has dot `.`. Keep it simple and use slash `/` as delimiter. – alvits Apr 18 '14 at 21:44
An awk
way of doing it would be:
awk -F'/' '{print $(NF-1)}' <<< "/from/here/to/there.txt"
Explanation:
-F'/'
sets field separator as "/"- print the second last field
$(NF-1)
<<<
uses anything after it as standard input (wiki explanation)

- 3,159
- 2
- 24
- 26
One more way
IFS=/ read -ra x <<<"/from/here/to/there.txt" && printf "%s\n" "${x[-2]}"

- 22,736
- 7
- 53
- 82
This question is something like THIS.
For solving that you can do:
DirPath="/from/here/to/there.txt"
DirPath="$(dirname $DirPath)"
DirPath="$(basename $DirPath)"
echo "$DirPath"
As my friend said this is possible as well:
basename `dirname "/from/here/to/there.txt"`
In order to get any part of your path you could do:
echo "/from/here/to/there.txt" | awk -F/ '{ print $2 }'
OR
echo "/from/here/to/there.txt" | awk -F/ '{ print $3 }'
OR
etc
The top answer is absolutely correct for the question asked. In a more generic case with the needed directory in the middle of a long path, this approach leads to a hard to read code. For example :
dir="/very/long/path/where/THIS/needs/to/be/extracted/text.txt"
dir="$(dirname $dir)"
dir="$(dirname $dir)"
dir="$(dirname $dir)"
dir="$(dirname $dir)"
dir="$(dirname $dir)"
dir="$(basename $dir)"
In this case one can use:
IFS=/; set -- "/very/long/path/where/THIS/needs/to/be/extracted/text.txt"; set $1; echo $6
THIS

- 335
- 2
- 6