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.)
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.
Take a look at the man page for realpath
, I use that and something like:
CONTAININGDIR=$(realpath ${FILEPATH%/*})
to do what it sounds like you're trying to do.
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
}
$cat abs.sh
#!/bin/bash
echo "$(cd "$(dirname "$1")"; pwd -P)"
Some explanations:
- This script get relative path as argument
"$1"
- Then we get dirname part of that path (you can pass either dir or file to this script):
dirname "$1"
- Then we
cd "$(dirname "$1");
into this relative dir
pwd -P
and get absolute path. The -P
option will avoid symlinks
- As final step we
echo
it
Then run your script:
abs.sh your_file.txt
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.
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
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}