Question Façon fiable pour un script bash pour obtenir le chemin complet à lui-même? [dupliquer]


Cette question a déjà une réponse ici:

J'ai un script bash qui a besoin de connaître son chemin complet. J'essaie de trouver un moyen de le faire largement compatible sans finir avec des chemins relatifs ou funky. Je n'ai besoin de supporter que bash, pas sh, csh, etc.

Ce que j'ai trouvé jusqu'ici:

  1. La réponse acceptée à "Obtention du répertoire source d'un script Bash depuis l'intérieur"adresses obtenant le chemin du script via dirname $0, ce qui est bien, mais cela peut retourner un relatif chemin (comme .), ce qui pose problème si vous voulez changer de répertoire dans le script et que le chemin pointe toujours vers le répertoire du script. Encore, dirname fera partie du puzzle.

  2. La réponse acceptée à "Chemin absolu du script Bash avec OSX" (OS X spécifique, mais la réponse fonctionne indépendamment) donne une fonction qui va tester pour voir si $0 semble relatif et si oui sera pré-pend $PWD à lui. Mais le résultat peut toujours contenir des bits relatifs (bien qu’il soit globalement absolu) - par exemple, si le script est t dans le répertoire /usr/bin et vous êtes dans /usr et vous tapez bin/../bin/t pour l'exécuter (oui, c'est compliqué), vous vous retrouvez avec /usr/bin/../bin comme le chemin du répertoire du script. Lequel travaux, mais...

  3. le readlink Solution sur cette page, qui ressemble à ceci:

    # Absolute path to this script. /home/user/bin/foo.sh
    SCRIPT=$(readlink -f $0)
    # Absolute path this script is in. /home/user/bin
    SCRIPTPATH=`dirname $SCRIPT`
    

    Mais readlink n'est pas POSIX et apparemment la solution repose sur GNU readlink où BSD ne fonctionnera pas pour une raison quelconque (je n'ai pas accès à un système de type BSD pour vérifier).

Donc, différentes façons de le faire, mais ils ont tous leurs réserves.

Quel serait le meilleur moyen? Où "mieux" signifie:

  • Me donne le chemin absolu.
  • Prend des morceaux funky même lorsqu'ils sont invoqués de manière alambiquée (voir le commentaire sur # 2 ci-dessus). (Par exemple, canonicalise au moins modérément le chemin.)
  • Ne repose que sur des bash-ismes ou des choses qui sont presque sûres d'être sur les saveurs les plus populaires des systèmes * nix (systèmes GNU / Linux, BSD et BSD comme OS X, etc.).
  • Evite d'appeler des programmes externes si possible (par exemple, préfère les bash intégrés).
  • (Actualisé, Merci pour l'information, qui) Ne doit pas résoudre les liens symboliques (en fait, je préfère que cela les laisse seuls, mais ce n’est pas une exigence).

505
2018-01-23 13:24


origine


Réponses:


Voici ce que je suis venu avec (modifier: plus quelques réglages fournis par sfstewman, levigroker, Kyle Strand, et Rob Kennedy), qui semble correspondre le plus souvent à mes «meilleurs» critères:

SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"

Cette SCRIPTPATH la ligne semble particulièrement détournée, mais nous en avons besoin plutôt que SCRIPTPATH=`pwd` afin de gérer correctement les espaces et les liens symboliques.

Notez également que les situations ésotériques, telles que l'exécution d'un script qui ne provient pas d'un fichier dans un système de fichiers accessible (ce qui est parfaitement possible), ne sont pas traitées ici (ou dans l'une des autres réponses que j'ai vues ).


393
2018-06-20 07:11



Je suis surpris que le realpath commande n'a pas été mentionné ici. Ma compréhension est que c'est largement portable / porté.

Votre solution initiale devient:

SCRIPT=`realpath $0`
SCRIPTPATH=`dirname $SCRIPT`

Et pour laisser des liens symboliques non résolus selon votre préférence:

SCRIPT=`realpath -s $0`
SCRIPTPATH=`dirname $SCRIPT`

153
2018-02-02 04:03



La manière la plus simple de trouver un chemin canonique complet dans bash est d'utiliser cd et pwd:

ABSOLUTE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"

En utilisant ${BASH_SOURCE[0]} au lieu de $0 produit le même comportement indépendamment du fait que le script est appelé comme <name> ou source <name>


135
2018-06-15 12:21



Je viens de revoir ce numéro aujourd'hui et trouvé https://stackoverflow.com/a/246128/1034080. Il élabore une solution qui J'ai aussi utilisé dans le passé.

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Il y a plus de variantes à la réponse liée, par ex. pour le cas où le script lui-même est un lien symbolique.


37
2017-08-30 13:04



Obtenir le chemin absolu du script shell

Ne pas utiliser -f option dans readlink, donc devrait fonctionner dans bsd / mac-osx

Les soutiens

  • source ./script (Appelé par le . opérateur point)
  • Chemin absolu / chemin / vers / script
  • Chemin relatif comme ./script
  • /path/dir1/../dir2/dir3/../script
  • Appelé depuis un lien symbolique
  • Lorsque le lien symbolique est imbriqué, par exemple) foo->dir1/dir2/bar bar->./../doe doe->script
  • Lorsque l'appelant change le nom du script

Je cherche des cas de coin où ce code ne fonctionne pas. S'il vous plaît, faites-moi savoir.

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`]"

Utilisation connue

Scénario 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 PIPE, cela ne fonctionnera pas

wget -o /dev/null -O - http://host.domain/dir/script.sh |bash

Techniquement parlant, il est indéfini.
En pratique, il n'y a pas de moyen sensé de détecter cela. (le co-processus ne peut pas accéder à env du parent)


34
2017-09-09 19:01



Qu'en est-il de l'utilisation de:

SCRIPT_PATH=$(dirname `which $0`)

which imprime à stdout le chemin complet de l'exécutable qui aurait été exécuté lorsque l'argument passé avait été entré à l'invite du shell (ce que contient 0 $)

dirname supprime le suffixe de non-répertoire du nom de fichier

Par conséquent, ce que vous obtenez est le chemin complet du script, peu importe si le chemin a été spécifié ou non.


28
2018-05-09 17:06



Comme realpath n'est pas installé par défaut sur mon système Linux, les travaux suivants sont pour moi:

SCRIPT="$(readlink --canonicalize-existing "$0")"
SCRIPTPATH="$(dirname "$SCRIPT")"

$SCRIPT contiendra le chemin du fichier réel vers le script et $SCRIPTPATH le chemin réel du répertoire contenant le script.

Avant d'utiliser ceci, lisez les commentaires de cette réponse.


22
2018-03-24 16:11



Répondre à cette question très tard, mais j'utilise:

SCRIPT=$( readlink -m $( type -p $0 ))      # Full path to script
BASE_DIR=`dirname ${SCRIPT}`                # Directory script is run in
NAME=`basename ${SCRIPT}`                   # Actual name of script even if linked

11
2017-10-02 16:28