Obtenir le chemin du script actuel lorsqu'il est exécuté via un lien symbolique

59

J'ai un utilitaire composé de quelques répertoires avec des scripts bash et des fichiers de support qui seront déployés sur plusieurs machines, éventuellement dans un répertoire différent sur chaque machine. Les scripts doivent pouvoir référencer des chemins relatifs par rapport à eux-mêmes, donc je dois pouvoir obtenir le chemin du fichier en cours d'exécution.

Je suis conscient du dirname $0langage qui fonctionne parfaitement lorsque mon script est appelé directement. Malheureusement, il est souhaitable de pouvoir créer des liens symboliques vers ces scripts à partir d'un répertoire totalement différent tout en maintenant la logique de cheminement relatif.

Voici un exemple de la structure globale du driectory:

/
 |-usr/local/lib
 |  |-foo
 |  |  |-bin
 |  |  |  |-script.sh
 |  |  |-res
 |  |  |  |-resource_file.txt
 |-home/mike/bin
 |  |-link_to_script (symlink to /usr/local/lib/foo/bin/script.sh)

Comment puis - je référence fiable /usr/local/lib/foo/res/resource_file.txtde script.shsavoir si elle est invoquée par /usr/local/lib/foo/bin/script.shou ~mike/bin/link_to_script?

Mike Deck
la source

Réponses:

80

Essayez ceci comme solution polyvalente:

DIR="$(cd "$(dirname "$0")" && pwd)"

Dans le cas spécifique des liens symboliques suivants, vous pouvez également le faire:

DIR="$(dirname "$(readlink -f "$0")")"
Caleb
la source
Fonctionne parfaitement et est bien plus simple que ce que j’essayais. Merci!
Mike Deck
@ MikeDeck Profitez. Notez que j'ai corrigé certains problèmes de citations depuis la première publication ... vous pouvez utiliser une option de la dernière modification si vous avez parfois des espaces ou des caractères loufoques dans votre chemin. Même si cela n'a pas d'importance pour ce projet, vous pouvez copier le code à partir de vos propres scripts et avoir la meilleure option, alors!
Caleb
1
Je devrais clarifier, le second fonctionne parfaitement. La première solution que vous avez donnée ne fonctionne pas pour les liens symboliques sur mon système.
Mike Deck
4
@MikeDeck: La première solution fonctionne dans le cas typique où plusieurs répertoires sont liés symboliquement dans le chemin, mais ne vous aidera pas si le binaire final est un lien symbolique. C'est ce que le second parvient à prendre en charge.
Caleb
1
Ne fonctionne pas si le fichier de script est sourced (par exemple $ source ./sript.sh) . Cela fonctionne dans les deux cas:DIR="$(cd "$(dirname "$BASH_SOURCE")" && pwd)"
FractalSpace
7

une ligne:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))
diyisme
la source
2
Les réponses à une ligne ne sont généralement pas les plus utiles. Envisagez d’élargir votre réponse pour y inclure une explication, des liens ou une documentation qui appuierait davantage votre solution suggérée.
HalosGhost
1
en fait, vous n'avez pas besoin de faire cela, la version de readlink de la réponse originale fonctionne parfaitement si aucun lien symbolique n'est impliqué
THESorcerer
3

readlink -f ne fonctionne pas pour moi, j'ai cette erreur:

readlink: illegal option -- f
usage: readlink [-n] [file ...]

Mais cela fonctionne bien:

DIR="$(dirname "$(readlink "$0")")"
echo $DIR
Kevin Campion
la source
3
Ensuite, vous êtes sur un Mac et cela devrait répondre à votre question .
Isaac
Oui, je suis sur MacOs @isaac, mais je n'ai pas de question. J'ai posté la commande qui fonctionne de mon côté.
Kevin Campion
0

Un petit ajout au script ci-dessus. L'option -P de pwd suit les liens symboliques

DIR="$(cd "$(dirname "$0")" && pwd -P)"
utilisateur2108420
la source
7
Cela ne fonctionne que lorsque le lien symbolique fait partie de la structure de répertoires. Cela ne fonctionne pas lorsque le fichier lui-même est lié.
Oliver Gondža