bash - working - dirname $0




Obtenir le répertoire source d'un script Bash de l'intérieur (20)

Comment obtenir le chemin du répertoire dans lequel se trouve un script Bash , à l' intérieur de ce script?

Par exemple, supposons que je souhaite utiliser un script Bash en tant que lanceur pour une autre application. Je souhaite remplacer le répertoire de travail par celui où se trouve le script Bash, afin de pouvoir utiliser les fichiers de ce répertoire, comme suit:

$ ./application

Ceci est spécifique à Linux, mais vous pouvez utiliser:

SELF=$(readlink /proc/$$/fd/255)

Ceci obtient le répertoire de travail actuel sur Mac OS X 10.6.6:

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

Essayez d'utiliser:

real=$(realpath $(dirname $0))

J'ai comparé beaucoup de réponses données et mis au point des solutions plus compactes. Ceux-ci semblent gérer tous les cas extrêmes qui découlent de votre combinaison préférée de:

  • Chemins absolus ou chemins relatifs
  • Liens symboliques de fichiers et répertoires
  • Invocation en tant que script , script bash script bash -c script source script ou . script . script
  • Espaces, tabulations, nouvelles lignes, unicode, etc. dans des répertoires et / ou un nom de fichier
  • Les noms de fichiers commençant par un trait d'union

Si vous utilisez Linux, il semble que l'utilisation du handle de proc soit la meilleure solution pour localiser la source entièrement résolue du script en cours d'exécution (dans une session interactive, le lien pointe vers le /dev/pts/X ):

resolved="$(readlink /proc/$$/fd/255 && echo X)" && resolved="${resolved%$'\nX'}"

Cela a un peu de laideur, mais le correctif est compact et facile à comprendre. Nous n'utilisons pas que des primitives bash, mais cela me readlink car readlink simplifie considérablement la tâche. echo X ajoute un X à la fin de la chaîne de variable afin que les espaces finaux du nom de fichier ne soient pas consommés et que le paramètre de substitution ${VAR%X} à la fin de la ligne supprime le X Parce que readlink ajoute une nouvelle ligne (qui serait normalement utilisée dans la substitution de commande si ce n'était de la supercherie précédente), nous devons également nous en débarrasser. Ceci est plus facilement réalisé en utilisant le schéma de citation $'' , ce qui nous permet d'utiliser des séquences d'échappement telles que \n pour représenter les nouvelles lignes (c'est également ainsi que vous pouvez facilement créer des répertoires et des fichiers nommés de manière sournoise).

Ce qui précède devrait couvrir vos besoins en matière de localisation du script en cours d’exécution sous Linux, mais si vous n’avez pas le système de fichiers proc à votre disposition, ou si vous essayez de localiser le chemin entièrement résolu d’un autre fichier, alors peut-être vous ' Vous trouverez le code ci-dessous utile. Ce n'est qu'une légère modification de la ligne précédente. Si vous jouez avec des noms de répertoire / fichier étranges, vérifier la sortie avec ls et readlink est informatif, car ls produira des chemins "simplifiés", en remplaçant ? pour des choses comme les nouvelles lignes.

absolute_path=$(readlink -e -- "${BASH_SOURCE[0]}" && echo x) && absolute_path=${absolute_path%?x}
dir=$(dirname -- "$absolute_path" && echo x) && dir=${dir%?x}
file=$(basename -- "$absolute_path" && echo x) && file=${file%?x}

ls -l -- "$dir/$file"
printf '$absolute_path: "%s"\n' "$absolute_path"

Je ne pense pas que ce soit aussi facile que d'autres l'ont imaginé. pwd ne fonctionne pas, car le répertoire en cours n'est pas nécessairement le répertoire avec le script. $ 0 n'a pas toujours l'information non plus. Examinez les trois manières suivantes d’appeler un script.

./script

/usr/bin/script

script

Dans les première et troisième manières, $ 0 n'a pas les informations de chemin complet. Dans les deuxième et troisième, les personnes handicapées ne travaillent pas. La seule façon d'obtenir le répertoire de la troisième manière serait de parcourir le chemin et de trouver le fichier avec la correspondance correcte. Fondamentalement, le code devrait refaire ce que le système d'exploitation fait.

Une façon de faire ce que vous demandez est simplement de coder en dur les données dans le répertoire / usr / share et de les référencer par chemin complet. Les données ne doivent pas être dans le répertoire / usr / bin de toute façon, donc c'est probablement la chose à faire.


Je voudrais utiliser quelque chose comme ça:

# retrieve the full pathname of the called script
scriptPath=$(which $0)

# check whether the path is a link or not
if [ -L $scriptPath ]; then

    # it is a link then retrieve the target path and get the directory name
    sourceDir=$(dirname $(readlink -f $scriptPath))

else

    # otherwise just get the directory name of the script path
    sourceDir=$(dirname $scriptPath)

fi

Pour les systèmes ayant GNU coreutils readlink (par exemple, linux):

$(readlink -f "$(dirname "$0")")

Inutile d'utiliser BASH_SOURCE lorsque $0 contient le nom du fichier de script.


Réponse courte:

`dirname $0`

ou (de preferably ):

$(dirname "$0")

Utilisez le nom de dirname "$0" :

#!/bin/bash
echo "The script you are running has basename `basename "$0"`, dirname `dirname "$0"`"
echo "The present working directory is `pwd`"

utiliser pwd seul ne fonctionnera pas si vous n'exécutez pas le script à partir du répertoire dans lequel il se trouve.

[[email protected] ~]$ pwd
/home/matt
[[email protected] ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[[email protected] ~]$ cd /tmp
[[email protected] tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp

Voici la manière simple et correcte:

actual_path=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$actual_path")

Explication:

  • ${BASH_SOURCE[0]} - le chemin complet du script. La valeur de this sera correcte même lors de la création du script. Par exemple, la source <(echo 'echo $0') affiche bash , alors que son remplacement par ${BASH_SOURCE[0]} affichera le chemin complet du script. (Bien entendu, cela suppose que vous puissiez prendre une dépendance à Bash.)

  • readlink -f - readlink -f récursive des liens symboliques dans le chemin spécifié. C'est une extension GNU, et non disponible sur (par exemple) les systèmes BSD. Si vous utilisez un Mac, vous pouvez utiliser Homebrew pour installer GNU coreutils et le remplacer par greadlink -f .

  • Et bien sûr, dirname obtient le répertoire parent du chemin.


Vous pouvez utiliser $ BASH_SOURCE

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

Notez que vous devez utiliser #! / Bin / bash et non #! / Bin / sh car c'est une extension bash


$_ vaut la peine d'être mentionné comme alternative à 0 $. Si vous exécutez un script à partir de bash, la réponse acceptée peut être réduite à:

DIR="$( dirname "$_" )"

Notez que ceci doit être la première déclaration de votre script.


Aucun de ceux-ci ne fonctionnait pour un script bash lancé par Finder sous OS X - j'ai fini par utiliser:

SCRIPT_LOC="`ps -p $$ | sed /PID/d | sed s:.*/Network/:/Network/: |
sed s:.*/Volumes/:/Volumes/:`"

Pas joli, mais ça fait le travail.


C’est le seul moyen que j’ai trouvé de dire de manière fiable:

SCRIPT_DIR=$(dirname $(cd "$(dirname "$BASH_SOURCE")"; pwd))

Essayez la solution multi-compatible suivante:

CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"

Les commandes as realpathou readlinkne sont pas toujours disponibles (selon le système d'exploitation) et ${BASH_SOURCE[0]}sont disponibles uniquement dans le shell bash.

Sinon, vous pouvez essayer la fonction suivante dans bash:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

Cette fonction prend 1 argument. Si l'argument a déjà un chemin absolu, affichez-le tel quel, sinon $PWDaffichez l'argument variable + nom du fichier (sans ./préfixe).

En relation:


La meilleure solution compacte à mon avis serait:

"$( cd "$( echo "${BASH_SOURCE[0]%/*}" )"; pwd )"

Il n'y a aucune confiance en rien d'autre que Bash. L'utilisation de dirname, readlinket basenameconduira éventuellement à des problèmes de compatibilité, afin qu'ils soient mieux évités si possible.


Hmm, si dans le chemin basename & dirname ne vont tout simplement pas le couper et qu'il est difficile de parcourir le chemin (que faire si le parent n'a pas exporté PATH!) Cependant, le shell doit avoir un handle ouvert dans son script, et en bash le handle est # 255.

SELF=`readlink /proc/$$/fd/255`

travaille pour moi.


#!/bin/sh
PRG="$0"

# need this for relative symlinks
while [ -h "$PRG" ] ; do
   PRG=`readlink "$PRG"`
done

scriptdir=`dirname "$PRG"`

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

est un one-liner utile qui vous donnera le nom de répertoire complet du script, peu importe d'où il est appelé.

Cela fonctionnera tant que le dernier composant du chemin utilisé pour trouver le script ne sera pas un lien symbolique (les liens de répertoire sont OK). Si vous souhaitez également résoudre des liens vers le script lui-même, vous avez besoin d'une solution multiligne:

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"

Ce dernier fonctionnera avec n’importe quelle combinaison d’alias, source , bash -c , liens symboliques, etc.

Attention: si vous cd dans un répertoire différent avant d'exécuter ce fragment, le résultat peut être incorrect! Aussi, faites attention aux $CDPATH .

Pour comprendre son fonctionnement, essayez d’exécuter ce formulaire plus détaillé:

#!/bin/bash

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  TARGET="$(readlink "$SOURCE")"
  if [[ $TARGET == /* ]]; then
    echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
    SOURCE="$TARGET"
  else
    DIR="$( dirname "$SOURCE" )"
    echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
    SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
  fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
  echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"

Et cela affichera quelque chose comme:

SOURCE './scriptdir.sh' is a relative symlink to 'sym2/scriptdir.sh' (relative to '.')
SOURCE is './sym2/scriptdir.sh'
DIR './sym2' resolves to '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
DIR is '/home/ubuntu/dotfiles/fo fo/real/real1/real2'

SCRIPT_DIR=$( cd ${0%/*} && pwd -P )






directory