How to extract directory path from file path?

Bash

Bash Problem Overview


In Bash, if VAR="/home/me/mydir/file.c", how do I get "/home/me/mydir"?

Bash Solutions


Solution 1 - Bash

dirname and basename are the tools you're looking for for extracting path components:

$ VAR='/home/pax/file.c'
$ DIR="$(dirname "${VAR}")" ; FILE="$(basename "${VAR}")"
$ echo "[${DIR}] [${FILE}]"
[/home/pax] [file.c]

They're not internal bash commands but they are part of the POSIX standard - see dirname and basename. Hence, they're probably available on, or can be obtained for, most platforms that are capable of running bash.

Solution 2 - Bash

$ export VAR=/home/me/mydir/file.c
$ export DIR=${VAR%/*}
$ echo "${DIR}"
/home/me/mydir

$ echo "${VAR##*/}"
file.c

To avoid dependency with basename and dirname

Solution 3 - Bash

On a related note, if you only have the filename or relative path, dirname on its own won't help. For me, the answer ended up being readlink.

fname='txtfile'    
echo $(dirname "$fname")                # output: .
echo $(readlink -f "$fname")            # output: /home/me/work/txtfile

You can then combine the two to get just the directory.

echo $(dirname $(readlink -f "$fname")) # output: /home/me/work

Solution 4 - Bash

If you care target files to be symbolic link, firstly you can check it and get the original file. The if clause below may help you.

if [ -h $file ]
then
 base=$(dirname $(readlink $file))
else
 base=$(dirname $file)
fi

Solution 5 - Bash

HERE=$(cd $(dirname $BASH_SOURCE) && pwd)

where you get the full path with new_path=$(dirname ${BASH_SOURCE[0]}). You change current directory with cd new_path and then run pwd to get the full path to the current directory.

Solution 6 - Bash

I was playing with this and came up with an alternative.

$ VAR=/home/me/mydir/file.c

$ DIR=`echo $VAR |xargs dirname`

$ echo $DIR
/home/me/mydir

The part I liked is it was easy to extend backup the tree:

$ DIR=`echo $VAR |xargs dirname |xargs dirname |xargs dirname`

$ echo $DIR
/home

Solution 7 - Bash

You could try something like this using approach for How to find the last field using 'cut':

Explanation

  • rev reverses /home/user/mydir/file_name.c to be c.eman_elif/ridym/resu/emoh/
  • cut uses / as the delimiter, and chooses the second field, which is ridym/resu/emoh/, which deletes string up to the first occurrence of /
  • lastly, we reverse it again to get /home/user/mydir
$ VAR="/home/user/mydir/file_name.c"
$ echo $VAR | rev | cut -d"/" -f2- | rev
/home/user/mydir

Solution 8 - Bash

Here is a script I used for recursive trimming. Replace $1 with the directory you want, of course.

BASEDIR=$1
IFS=$'\n'
cd "$BASEDIR"
 for f in $(find . -type f -name ' *')
 do 
	DIR=$(dirname "$f")
	DIR=${DIR:1}
	cd "$BASEDIR$DIR"
    rename 's/^ *//' *
 done

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTalespin_KitView Question on Stackoverflow
Solution 1 - BashpaxdiabloView Answer on Stackoverflow
Solution 2 - BashEmmanuel DevauxView Answer on Stackoverflow
Solution 3 - BashjerblackView Answer on Stackoverflow
Solution 4 - BashTahsin TurkozView Answer on Stackoverflow
Solution 5 - BashaerijmanView Answer on Stackoverflow
Solution 6 - BashEurospooferView Answer on Stackoverflow
Solution 7 - BashalperView Answer on Stackoverflow
Solution 8 - BashkmchenView Answer on Stackoverflow