[bash] How to get a file directory path from file path?

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

This question is related to bash

The answer is


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

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.


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

$ 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


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 dot (ie /) as the delimiter, and chooses the first field, which is c.eman_elif
  • lastly, we reverse it again to get file_name.c
$ VAR="/home/user/mydir/file_name.c"
$ echo $VAR | rev | cut -f1 -d"/" | rev
file_name.c

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

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