How do I get the absolute directory of a file in bash?

LinuxBashShell

Linux Problem Overview


I have written a bash script that takes an input file as an argument and reads it.
This file contains some paths (relative to its location) to additional files used.

I would like the script to go to the folder containing the input file, to execute further commands.

So, how do I get the folder (and just the folder) from an input file? (In linux.)

Linux Solutions


Solution 1 - Linux

To get the full path use:

readlink -f relative/path/to/file

To get the directory of a file:

dirname relative/path/to/file

You can also combine the two:

dirname $(readlink -f relative/path/to/file)

If readlink -f is not available on your system you can use this*:

function myreadlink() {
  (
  cd "$(dirname $1)"         # or  cd "${1%/*}"
  echo "$PWD/$(basename $1)" # or  echo "$PWD/${1##*/}"
  )
}

Note that if you only need to move to a directory of a file specified as a relative path, you don't need to know the absolute path, a relative path is perfectly legal, so just use:

cd $(dirname relative/path/to/file)

if you wish to go back (while the script is running) to the original path, use pushd instead of cd, and popd when you are done.


* While myreadlink above is good enough in the context of this question, it has some limitation relative to the readlink tool suggested above. For example it doesn't correctly follow a link to a file with different basename.

Solution 2 - Linux

Take a look at realpath which is available on GNU/Linux, FreeBSD and NetBSD, but not OpenBSD 6.8. I use something like:

CONTAININGDIR=$(realpath ${FILEPATH%/*})

to do what it sounds like you're trying to do.

Solution 3 - Linux

This will work for both file and folder:

absPath(){
    if [[ -d "$1" ]]; then
        cd "$1"
        echo "$(pwd -P)"
    else 
        cd "$(dirname "$1")"
        echo "$(pwd -P)/$(basename "$1")"
    fi
}

Solution 4 - Linux

$cat abs.sh
#!/bin/bash
echo "$(cd "$(dirname "$1")"; pwd -P)"

Some explanations:

  1. This script get relative path as argument "$1"
  2. Then we get dirname part of that path (you can pass either dir or file to this script): dirname "$1"
  3. Then we cd "$(dirname "$1"); into this relative dir
  4. pwd -P and get absolute path. The -P option will avoid symlinks
  5. As final step we echo it

Then run your script:

abs.sh your_file.txt

Solution 5 - Linux

Try our new Bash library product realpath-lib over at GitHub that we have given to the community for free and unencumbered use. It's clean, simple and well documented so it's great to learn from. You can do:

get_realpath <absolute|relative|symlink|local file path>

This function is the core of the library:

if [[ -f "$1" ]]
then
    # file *must* exist
    if cd "$(echo "${1%/*}")" &>/dev/null
    then
        # file *may* not be local
        # exception is ./file.ext
        # try 'cd .; cd -;' *works!*
        local tmppwd="$PWD"
        cd - &>/dev/null
    else
        # file *must* be local
        local tmppwd="$PWD"
    fi
else
    # file *cannot* exist
    return 1 # failure
fi

# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success

}

It's Bash 4+, does not require any dependencies and also provides get_dirname, get_filename, get_stemname and validate_path.

Solution 6 - Linux

Problem with the above answer comes with files input with "./" like "./my-file.txt"

Workaround (of many):

    myfile="./somefile.txt"
	FOLDER="$(dirname $(readlink -f "${ARG}"))"
    echo ${FOLDER}

Solution 7 - Linux

I have been using readlink -f works on linux

so

FULL_PATH=$(readlink -f filename)
DIR=$(dirname $FULL_PATH)

PWD=$(pwd)

cd $DIR

#<do more work>

cd $PWD

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
QuestionBobMcGeeView Question on Stackoverflow
Solution 1 - LinuxChen LevyView Answer on Stackoverflow
Solution 2 - LinuxRichard SitzeView Answer on Stackoverflow
Solution 3 - LinuxJahidView Answer on Stackoverflow
Solution 4 - LinuxEugen KonkovView Answer on Stackoverflow
Solution 5 - LinuxAsymLabsView Answer on Stackoverflow
Solution 6 - LinuxMike QView Answer on Stackoverflow
Solution 7 - LinuxMehul RathodView Answer on Stackoverflow