Trouver un chemin absolu à partir d'un script

10

Dans un script, j'obtiens $0le chemin relatif possible vers celui-ci. Pour le convertir en absolu, j'ai trouvé cette solution que je ne comprends pas:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

Mon problème est la magie à l'intérieur de ${0%/*}et ${0##*/}. Il semble que le premier extrait le nom du répertoire et le dernier extrait le nom du fichier, je ne comprends pas comment.

maaartinus
la source
2
Cela utilise l'expansion des paramètres, mais cela n'a pas fonctionné pour moi. Si votre script ne sera utilisé que sous Linux, vous pouvez utiliser readlink -f $0pour obtenir le chemin canonique.
Shawn J.Goff
1
@Shawn: 1 super commentaire vote parce que vous avez introduit la bonne pensée: "Cela utilise l'expansion des paramètres, mais cela n'a pas fonctionné pour moi". L' dirnameutilité est utile ici.
D4RIO
mywiki.wooledge.org/BashFAQ/028 et cyberciti.biz/faq/… dit que BASH_SOURCEc'est mieux que $0, comme le $0donne la commande tapée par l'utilisateur, qui pourrait ne pas être le script en cours d'exécution.
Joel Purra

Réponses:

8

Définitions:

${string%substring} supprime la correspondance la plus courte $substringde la fin de $string.

${string##substring}supprime la plus longue correspondance de $substringdepuis le début de $string.

Votre exemple:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

${0%/*} supprime tout après la dernière barre oblique, vous donnant le nom de répertoire du script (qui peut être un chemin relatif).

${0##*/} supprime tout jusqu'à la dernière barre oblique, vous donnant simplement le nom du script.

Ainsi, cette commande se transforme en répertoire du script et concatène le répertoire de travail actuel (donné par $PWD) et le nom du script vous donnant le chemin absolu.

Pour voir ce qui se passe, essayez:

echo ${0%/*}
echo ${0##*/}
dogbane
la source
Ajoutez des guillemets doubles autour de toutes les extensions de variables pour gérer (presque tous) les noms de fichiers contenant des caractères spéciaux du shell.
Gilles 'SO- arrête d'être méchant'
10

Shawn avait la solution la plus simple: readlink -f $0. Si vous voulez être absolument sûr de gérer les noms de fichiers étranges, vous pouvez utiliser ceci:

absolute_path_x="$(readlink -fn -- "$0"; echo x)"
absolute_path="${absolute_path_x%x}"

Documentation

l0b0
la source
1
Bon de voir les nouvelles lignes finales correctement gérées. Malheureusement, il readlink -fnest spécifique à Linux, NetBSD et OpenBSD.
Gilles 'SO- arrête d'être méchant'
4

Voici un moyen plus sûr et plus lisible de faire ce travail:

abspath=$(unset CDPATH && cd "$(dirname "$0")" && echo $PWD/$(basename "$0"))

Remarques:

  • S'il $0s'agit d'un nom de fichier nu sans chemin d'accès précédent, le script d'origine échouera mais celui donné ici fonctionnera. (Pas un problème avec $0mais pourrait être dans d'autres applications.)
  • L'une ou l'autre approche échouera si le chemin d'accès au fichier n'existe pas réellement. (Pas de problème avec $0, mais pourrait être dans d'autres applications.)
  • Le unsetest essentiel si votre utilisateur peut avoir CDPATHdéfini.
  • Contrairement à readlink -fou realpath, cela fonctionnera sur les versions non Linux d'Unix (par exemple, Mac OS X).
Matthias Fripp
la source
2

Si vous voulez apprendre l'expansion des paramètres du shell, vous pouvez le lire à partir d' ici , mais l'expansion n'est pas toujours un bon choix. Dans ce cas, presque tous les systèmes de type Unix ont 2 bons utilitaires:

basename
dirname

Le premier extraira le nom du fichier, tandis que le second extraira le chemin, donc, si vous avez $ 0, dites:

dirname $0

Et vous aurez le chemin.

À votre santé

D4RIO
la source
dirname peut renvoyer des chemins relatifs
opticyclic
0

Présentation de pwd, le module intégré bash. Également trouvé dans le paquet GNU coreutils.

$ sh ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
$0: ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
cheeky binary from /home/jaroslav/tmp (/home/jaroslav/tmp)

$ cat /home/jaroslav/tmp/somewhere.sh

abs=$( cd `dirname "$0"` ; pwd -P)
absBin=$( cd `dirname "$0"` ; /bin/pwd -P)
echo \$0: $0
echo cheeky binary from $abs \($absBin\)
Ярослав Рахматуллин
la source