Comment obtenir le nom de chemin absolu du script shell sur MacOS?
readlink -f
n'existe pas sur MacOS. La seule solution de travail pour Mac OS que j'ai réussi à trouver sur le net va comme ceci:
if [[ $(echo $0 | awk '/^//') == $0 ]]; then
ABSPATH=$(dirname $0)
else
ABSPATH=$PWD/$(dirname $0)
fi
Quelqu'un peut-il suggérer quelque chose de plus élégant à cette tâche apparemment triviale?
11 réponses
Une autre option (aussi plutôt laide):
ABSPATH=$(cd "$(dirname "$0")"; pwd)
Récupère le chemin absolu du script shell
Creusé quelques vieux scripts de mon .bashrc, et mis à jour la syntaxe un peu, a ajouté une suite de tests.
Prend en charge
- source ./ script (lorsqu'il est appelé par l'opérateur point
.
) - chemin absolu / chemin / vers / script
- chemin relatif comme ./ script
- /chemin/dir1/../dir2/dir3/../ script
- lorsqu'il est appelé à partir du lien symbolique
- lorsque le lien symbolique est imbriqué par exemple)
foo->dir1/dir2/bar bar->./../doe doe->script
- Lorsque l'appelant modifie les scripts nom
Il a été testé et utilisé dans de vrais projets avec succès, mais il peut y avoir des cas de coin dont je ne suis pas au courant.
Si vous étiez en mesure de trouver une telle situation, s'il vous plaît laissez-moi savoir.
(Pour un, je sais que cela ne fonctionne pas sur le shell sh)
Code
pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
while([ -h "${SCRIPT_PATH}" ]) do
cd "`dirname "${SCRIPT_PATH}"`"
SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
done
cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
SCRIPT_PATH="`pwd`";
popd > /dev/null
echo "srcipt=[${SCRIPT_PATH}]"
echo "pwd =[`pwd`]"
Issuse connu
Script doit être sur le disque quelque part, que ce soit sur un réseau. Si vous essayez d'exécuter ce script à partir d'un TUYAU, elle ne fonctionnera pas
wget -o /dev/null -O - http://host.domain/dir/script.sh |bash
Techniquement en parlant, elle n'est pas définie.
Pratiquement parlant, il n'y a pas de moyen sain de détecter cela.
Cas de Test utilisé
Et le cas de test actuel qui vérifie que cela fonctionne.
#!/bin/bash
# setup test enviroment
mkdir -p dir1/dir2
mkdir -p dir3/dir4
ln -s ./dir1/dir2/foo bar
ln -s ./../../dir3/dir4/test.sh dir1/dir2/foo
ln -s ./dir1/dir2/foo2 bar2
ln -s ./../../dir3/dir4/doe dir1/dir2/foo2
cp test.sh ./dir1/dir2/
cp test.sh ./dir3/dir4/
cp test.sh ./dir3/dir4/doe
P="`pwd`"
echo "--- 01"
echo "base =[${P}]" && ./test.sh
echo "--- 02"
echo "base =[${P}]" && `pwd`/test.sh
echo "--- 03"
echo "base =[${P}]" && ./dir1/dir2/../../test.sh
echo "--- 04"
echo "base =[${P}/dir3/dir4]" && ./bar
echo "--- 05"
echo "base =[${P}/dir3/dir4]" && ./bar2
echo "--- 06"
echo "base =[${P}/dir3/dir4]" && `pwd`/bar
echo "--- 07"
echo "base =[${P}/dir3/dir4]" && `pwd`/bar2
echo "--- 08"
echo "base =[${P}/dir1/dir2]" && `pwd`/dir3/dir4/../../dir1/dir2/test.sh
echo "--- 09"
echo "base =[${P}/dir1/dir2]" && ./dir1/dir2/test.sh
echo "--- 10"
echo "base =[${P}/dir3/dir4]" && ./dir3/dir4/doe
echo "--- 11"
echo "base =[${P}/dir3/dir4]" && ./dir3/dir4/test.sh
echo "--- 12"
echo "base =[${P}/dir3/dir4]" && `pwd`/dir3/dir4/doe
echo "--- 13"
echo "base =[${P}/dir3/dir4]" && `pwd`/dir3/dir4/test.sh
echo "--- 14"
echo "base =[${P}/dir3/dir4]" && `pwd`/dir1/dir2/../../dir3/dir4/doe
echo "--- 15"
echo "base =[${P}/dir3/dir4]" && `pwd`/dir1/dir2/../../dir3/dir4/test.sh
echo "--- 16"
echo "base s=[${P}]" && source test.sh
echo "--- 17"
echo "base s=[${P}]" && source `pwd`/test.sh
echo "--- 18"
echo "base s=[${P}/dir1/dir2]" && source ./dir1/dir2/test.sh
echo "--- 19"
echo "base s=[${P}/dir3/dir4]" && source ./dir1/dir2/../../dir3/dir4/test.sh
echo "--- 20"
echo "base s=[${P}/dir3/dir4]" && source `pwd`/dir1/dir2/../../dir3/dir4/test.sh
echo "--- 21"
pushd . >/dev/null
cd ..
echo "base x=[${P}/dir3/dir4]"
./`basename "${P}"`/bar
popd >/dev/null
PurpleFox alias GreenFox
Notez Également que homebrew
's (http://brew.sh) coreutils
forfait comprend realpath
(lien créé dans/opt/local/bin
).
$ realpath bin
/Users/nhed/bin
En utilisant bash je suggère cette approche. Vous commencez par cd dans le répertoire, puis vous prenez le répertoire actuel en utilisant pwd. Après cela, vous devez revenir à l'ancien répertoire pour assurer votre script ne crée pas d'effets secondaires à un autre script en l'appelant.
cd "$(dirname -- "$0")"
dir="$PWD"
echo "$dir"
cd - > /dev/null
Cette solution est sûre avec un chemin complexe. Vous n'aurez jamais de problèmes avec des espaces ou des charaters spéciaux si vous mettez les citations.
Note: le/dev / null est require ou "cd -" affiche le chemin vers lequel il retourne.
Si cela ne vous dérange pas d'utiliser perl:
ABSPATH=$(perl -MCwd=realpath -e "print realpath '$0'")
Pouvez-vous essayer quelque chose comme ça dans votre script?
echo $(pwd)/"$0"
Dans ma machine, il montre:
/home/barun/codes/ns2/link_down/./test.sh
Qui est le nom de chemin absolu du script shell.
C'est ce que j'utilise, peut avoir besoin d'un tweak ici ou là
abspath ()
{
case "${1}" in
[./]*)
local ABSPATH="$(cd ${1%/*}; pwd)/${1##*/}"
echo "${ABSPATH/\/\///}"
;;
*)
echo "${PWD}/${1}"
;;
esac
}
C'est pour tout fichier et de malédiction, vous pouvez simplement appeler comme abspath ${0}
Le premier cas traite des chemins relatifs en cd - ing au chemin et en laissant pwd le comprendre
Le deuxième cas concerne le traitement d'un fichier local (où ${1##/} n'aurait pas fonctionné)
Cela ne tente pas d'annuler les liens symboliques!
Cela fonctionne tant que ce n'est pas un lien symbolique, et est peut-être légèrement moins moche:
ABSPATH=$(dirname $(pwd -P $0)/${0#\.\/})
Si vous utilisez ksh, le paramètre ${.sh.file}
est défini sur le chemin absolu du script. Pour obtenir le répertoire parent du script: ${.sh.file%/*}
J'utilise la fonction ci-dessous pour émuler "readlink-f" pour les scripts qui doivent s'exécuter à la fois sur linux et Mac OS X.
#!/bin/bash
# Works on both linux and Mac OS X.
function read-link() {
local path=$1
if [ -d $path ] ; then
local abspath=$(cd $path; pwd)
else
local prefix=$(cd $(dirname -- $path) ; pwd)
local suffix=$(basename $path)
local abspath="$prefix/$suffix"
fi
echo $abspath
}
# Example usage.
read-link $1
dirname -- $(read-link $1)
J'ai trouvé cela utile pour les liens symboliques / liens dynamiques-fonctionne avec GNU readlink seulement (à cause du drapeau-f):
# detect if GNU readlink is available on OS X
if [ "$(uname)" = "Darwin" ]; then
which greadlink > /dev/null || {
printf 'GNU readlink not found\n'
exit 1
}
alias readlink="greadlink"
fi
# create a $dirname variable that contains the file dir
dirname=$(dirname "$(readlink -f "$0")")
# use $dirname to find a relative file
cat "$dirname"/foo/bar.txt