Comme arguments de mon script, il y a des chemins de fichiers. Celles-ci peuvent bien sûr être relatives (ou contenir ~). Mais pour les fonctions que j'ai écrites, j'ai besoin de chemins absolus, mais leurs liens symboliques ne sont pas résolus.
Y at-il une fonction pour cela?
MY_PATH=$(readlink -f $YOUR_ARG)
résoudra les chemins relatifs tels que "./"
et "../"
Considérez ceci également ( 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
http://www.linuxquestions.org/questions/programming-9/bash-script-return-full-path-and-filename-680368/page3.html présente les éléments suivants
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
}
qui utilise pushd
/popd
pour entrer dans un état où pwd
est utile.
Simple one-liner:
function abs_path {
(cd "$(dirname '$1')" &>/dev/null && printf "%s/%s" "$PWD" "${1##*/}")
}
Usage:
function do_something {
local file=$(abs_path $1)
printf "Absolute path to %s: %s\n" "$1" "$file"
}
do_something $HOME/path/to/some\ where
J'essaie toujours de comprendre comment je peux le faire complètement oublier que le chemin existe ou non (afin qu'il puisse également être utilisé lors de la création de fichiers).
Cela me convient sous OS X: $(cd SOME_DIRECTORY 2> /dev/null && pwd -P)
Cela devrait fonctionner n'importe où. Les autres solutions semblaient trop compliquées.
sur OS X, vous pouvez utiliser
stat -f "%N" YOUR_PATH
sur linux, vous aurez peut-être realpath
exécutable. sinon, ce qui suit pourrait fonctionner (pas seulement pour les liens):
readlink -c YOUR_PATH
Peut-être que ceci est plus lisible et n'utilise pas de sous-shell et ne change pas le répertoire actuel:
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
}
Utilisez readlink -f <relative-path>
, par exemple.
export FULLPATH=`readlink -f ./`
Il y a une autre méthode. Vous pouvez utiliser python imbriqué dans un script bash pour résoudre un chemin relatif.
abs_path=$(python3 - <<END
from pathlib import Path
path = str(Path("$1").expanduser().resolve())
print(path)
END
)
moi-même, j'ai juste remarqué que l'OP disait qu'il ne cherchait pas les liens symboliques résolus:
"Mais pour les fonctions que j'ai écrites, j'ai besoin de chemins absolus, mais leurs liens symboliques ne sont pas résolus."
Donc, suppose que ce n’est pas si approprié à sa question après tout. :)
Depuis que je suis confronté à cela de nombreuses fois au fil des ans, et cette fois-ci, j'avais besoin d'une version portable pur bash que je pouvais utiliser sur OSX et Linux, je me suis lancé et j'en ai écrit une:
La version vivante vit ici:
https://github.com/keen99/Shell-functions/tree/master/resolve_path
mais dans l’intérêt de SO, voici la version actuelle (j’estime qu’elle est bien testée, mais je suis ouvert aux commentaires!)
Ce n’est peut-être pas difficile de le faire fonctionner pour Plain Bourne Shell (sh), mais je n’ai pas essayé ... J'aime trop $ 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's a link.
#file or directory, we want to cd into it's 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
}
voici un exemple classique, grâce à brasser:
%% 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
utilisez cette fonction et elle retournera le chemin -real-:
%% 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