Expand possible relative path in bash

There are several file paths as arguments to my script. Of course, they can relate (or contain ~). But for the functions I wrote, I need absolute paths, but their symbolic links are not allowed.

Is there any function for this?

+57
bash absolute-path
Aug 19 '11 at 19:39
source share
10 answers

MY_PATH=$(readlink -f $YOUR_ARG) will allow relative paths such as "./" and "../"

Consider this also ( source ):

 #!/bin/bash dir_resolve() { cd "$1" 2>/dev/null || return $? # cd to desired directory; if fail, quell any error messages but return exit status echo "`pwd -P`" # output full, link-resolved path } # sample usage if abs_path="`dir_resolve \"$1\"`" then echo "$1 resolves to $abs_path" echo pwd: `pwd` # function forks subshell, so working directory outside function is not affected else echo "Could not reach $1" fi 
+53
Aug 19 '11 at 20:01
source share

http://www.linuxquestions.org/questions/programming-9/bash-script-return-full-path-and-filename-680368/page3.html has the following

 function abspath { if [[ -d "$1" ]] then pushd "$1" >/dev/null pwd popd >/dev/null elif [[ -e $1 ]] then pushd "$(dirname "$1")" >/dev/null echo "$(pwd)/$(basename "$1")" popd >/dev/null else echo "$1" does not exist! >&2 return 127 fi } 

which uses pushd / popd to transition to the state in which pwd is useful.

+35
Oct 26
source share

Simple single line:

 function abs_path { (cd "$(dirname '$1')" &>/dev/null && printf "%s/%s" "$PWD" "${1##*/}") } 

Using:

 function do_something { local file=$(abs_path $1) printf "Absolute path to %s: %s\n" "$1" "$file" } do_something $HOME/path/to/some\ where 

I'm still trying to figure out how I can make it completely forget whether the path exists or not (therefore, it can be used when creating files).

+15
Jun 12 '13 at 22:10
source share

This does the trick for me on OS X: $(cd SOME_DIRECTORY 2> /dev/null && pwd -P)

It should work anywhere. Other solutions seemed too complicated.

+8
Sep 28 '16 at 11:35
source share

in OS X you can use

 stat -f "%N" YOUR_PATH 

on linux you can have a realpath . if not, the following may work (not just for links):

 readlink -c YOUR_PATH 
+5
Dec 10
source share

Perhaps this is more readable and does not use a subshell and does not change the current directory:

 dir_resolve() { local dir=`dirname "$1"` local file=`basename "$1"` pushd "$dir" &>/dev/null || return $? # On error, return error code echo "`pwd -P`/$file" # output full, link-resolved path with filename popd &> /dev/null } 
+2
Jan 03 '14 at 10:34
source share

self edit, I just noticed that the OP said that it is not looking for allowed symbolic links:

"But the functions I wrote need absolute absolute paths, but their symbolic links are not allowed."

So guess that this is not the case with his question. :)

Since I have come across this many times over the years, and this time I need a clean portable version of bash that I could use on OSX and Linux, I went ahead and wrote one:

The live version lives here:

https://github.com/keen99/shell-functions/tree/master/resolve_path

but for SO, here is the current version (I feel that it is well tested ... but I am open to feedback!)

It may not be difficult to make it work for a simple bourne (sh) shell, but I have not tried ... I really like $ FUNCNAME. :)

 #!/bin/bash resolve_path() { #I'm bash only, please! # usage: resolve_path <a file or directory> # follows symlinks and relative paths, returns a full real path # local owd="$PWD" #echo "$FUNCNAME for $1" >&2 local opath="$1" local npath="" local obase=$(basename "$opath") local odir=$(dirname "$opath") if [[ -L "$opath" ]] then #it a link. #file or directory, we want to cd into it dir cd $odir #then extract where the link points. npath=$(readlink "$obase") #have to -L BEFORE we -f, because -f includes -L :( if [[ -L $npath ]] then #the link points to another symlink, so go follow that. resolve_path "$npath" #and finish out early, we're done. return $? #done elif [[ -f $npath ]] #the link points to a file. then #get the dir for the new file nbase=$(basename $npath) npath=$(dirname $npath) cd "$npath" ndir=$(pwd -P) retval=0 #done elif [[ -d $npath ]] then #the link points to a directory. cd "$npath" ndir=$(pwd -P) retval=0 #done else echo "$FUNCNAME: ERROR: unknown condition inside link!!" >&2 echo "opath [[ $opath ]]" >&2 echo "npath [[ $npath ]]" >&2 return 1 fi else if ! [[ -e "$opath" ]] then echo "$FUNCNAME: $opath: No such file or directory" >&2 return 1 #and break early elif [[ -d "$opath" ]] then cd "$opath" ndir=$(pwd -P) retval=0 #done elif [[ -f "$opath" ]] then cd $odir ndir=$(pwd -P) nbase=$(basename "$opath") retval=0 #done else echo "$FUNCNAME: ERROR: unknown condition outside link!!" >&2 echo "opath [[ $opath ]]" >&2 return 1 fi fi #now assemble our output echo -n "$ndir" if [[ "x${nbase:=}" != "x" ]] then echo "/$nbase" else echo fi #now return to where we were cd "$owd" return $retval } 

here is a classic example thanks to brew:

 %% ls -l `which mvn` lrwxr-xr-x 1 draistrick 502 29 Dec 17 10:50 /usr/local/bin/mvn@ -> ../Cellar/maven/3.2.3/bin/mvn 

use this function and it will return the -real path:

 %% cat test.sh #!/bin/bash . resolve_path.inc echo echo "relative symlinked path:" which mvn echo echo "and the real path:" resolve_path `which mvn` %% test.sh relative symlinked path: /usr/local/bin/mvn and the real path: /usr/local/Cellar/maven/3.2.3/libexec/bin/mvn 
0
Dec 24 '14 at 20:57
source share

Use readlink -f <relative-path> , for example

 export FULLPATH='readlink -f ./' 
0
Oct 25 '18 at 6:21
source share

There is another method. You can use python embedding in a bash script to determine the relative path.

 abs_path=$(python3 - <<END from pathlib import Path path = str(Path("$1").expanduser().resolve()) print(path) END ) 
0
Jun 04 '19 at 13:25
source share

Do you need to use only bash? I needed to do this, and I was tired of the difference between Linux and OS X. Therefore, I used PHP for a quick and dirty solution.

 #!/usr/bin/php <-- or wherever <?php { if($argc!=2) exit(); $fname=$argv[1]; if(!file_exists($fname)) exit(); echo realpath($fname)."\n"; } ?> 

I know this is not a very elegant solution, but it works.

-one
Apr 28 '13 at 5:07 on
source share



All Articles