À condition que vous ayez des autorisations d'exécution sur le répertoire courant - ou sur le répertoire à partir duquel vous avez exécuté votre script shell - si vous voulez un chemin absolu vers un répertoire, tout ce dont vous avez besoin est cd
.
Étape 10 de cd
la spécification de
Si l' -P
option est en vigueur, la $PWD
variable d'environnement doit être définie sur la chaîne qui serait sortie par pwd -P
. S'il n'y a pas suffisamment d'autorisations sur le nouveau répertoire ou sur l'un des parents de ce répertoire pour déterminer le répertoire de travail en cours, la valeur de la $PWD
variable d'environnement n'est pas spécifiée.
Et sur pwd -P
Le chemin d'accès écrit sur la sortie standard ne doit contenir aucun composant faisant référence à des fichiers de type lien symbolique. S'il existe plusieurs chemins d'accès que l' pwd
utilitaire pourrait écrire sur la sortie standard, un commençant par un caractère simple / barre oblique et un ou plusieurs commençant par deux caractères / barre oblique, il doit écrire le nom de chemin commençant par un caractère simple / barre oblique. Le chemin d'accès ne doit contenir aucun caractère / barre oblique inutile après le ou les deux premiers caractères / barre oblique.
C'est parce que cd -P
doit définir le répertoire de travail en cours sur ce qui pwd -P
devrait autrement être imprimé et qui cd -
doit imprimer le $OLDPWD
que cela fonctionne:
mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -
SORTIE
/home/mikeserv/test/ln
attendez ...
cd -P . ; cd . ; cd -
SORTIE
/home/mikeserv/test/dir
Et quand cd -
j'imprime avec j'imprime $OLDPWD
. cd
définit $PWD
dès que je suis cd -P .
$PWD
maintenant un chemin absolu vers /
- donc je n'ai pas besoin d'autres variables. Et en fait, je devrais même pas besoin de la fuite , .
mais il y a un comportement déterminé de réinitialisation $PWD
à $HOME
dans un shell interactif quand cd
est sans fioritures. C'est donc juste une bonne habitude à développer.
Donc, simplement faire ce qui précède sur le chemin d'accès ${0%/*}
devrait être plus que suffisant pour vérifier $0
le chemin d'accès de, mais dans le cas qui $0
est lui-même un lien logiciel, vous ne pouvez probablement pas y changer de répertoire, malheureusement.
Voici une fonction qui gérera cela:
zpath() { cd -P . || return
_out() { printf "%s$_zdlm\n" "$PWD/${1##*/}"; }
_cd() { cd -P "$1" ; } >/dev/null 2>&1
while [ $# -gt 0 ] && _cd .
do if _cd "$1"
then _out
elif ! [ -L "$1" ] && [ -e "$1" ]
then _cd "${1%/*}"; _out "$1"
elif [ -L "$1" ]
then ( while set -- "${1%?/}"; _cd "${1%/*}"; [ -L "${1##*/}" ]
do set " $1" "$(_cd -; ls -nd -- "$1"; echo /)"
set -- "${2#*"$1" -> }"
done; _out "$1"
); else ( PS4=ERR:\ NO_SUCH_PATH; set -x; : "$1" )
fi; _cd -; shift; done
unset -f _out _cd; unset -v _zdlm
}
Il s'efforce de faire autant que possible dans le shell actuel - sans invoquer de sous-shell - bien qu'il existe des sous-shell invoqués pour les erreurs et les liens logiciels qui ne pointent pas vers des répertoires. Cela dépend d'un shell compatible POSIX ls
et d'un _function()
espace compatible POSIX ainsi que d'un espace de noms propre . Il fonctionnera toujours très bien sans ce dernier, bien qu'il puisse remplacer alors unset
certaines fonctions shell actuelles dans ce cas. En général, toutes ces dépendances devraient être disponibles de manière assez fiable sur une machine Unix.
Appelé avec ou sans arguments, la première chose qu'il fait est réinitialisé $PWD
à sa valeur canonique - il résout tous les liens qu'il contient vers leurs cibles si nécessaire. Appelé sans arguments et c'est à peu près tout; mais appelé avec eux et il résoudra et canonisera le chemin pour chacun ou bien affichera un message pour stderr
pourquoi pas.
Parce qu'il fonctionne principalement dans le shell actuel, il devrait être capable de gérer une liste d'arguments de n'importe quelle longueur. Il recherche également la $_zdlm
variable (qui est également unset
affichée lorsqu'elle est terminée) et imprime sa valeur d' \n
échappement C immédiatement à droite de chacun de ses arguments, chacun étant toujours suivi également d'un seul caractère de ligne électronique.
Il change beaucoup de répertoire, mais, à part le mettre à sa valeur canonique, il n'affecte pas $PWD
, bien $OLDPWD
qu'il ne puisse en aucun cas être compté quand il est terminé.
Il essaie de quitter chacun de ses arguments dès qu'il le peut. Il essaie d'abord d' cd
entrer $1
. S'il le peut, il affiche le chemin canonique de l'argument vers stdout
. S'il ne le peut pas, il vérifie qu'il $1
existe et n'est pas un lien logiciel. Si c'est vrai, il s'imprime.
De cette façon, il gère tout argument de type de fichier auquel le shell a les droits d'adresser, sauf s'il $1
s'agit d'un lien symbolique qui ne pointe pas vers un répertoire. Dans ce cas, il appelle la while
boucle dans un sous-shell.
Il appelle ls
à lire le lien. Le répertoire courant doit d'abord être modifié à sa valeur initiale afin de gérer de manière fiable tous les chemins référents et ainsi, dans le sous-shell de substitution de commandes, la fonction:
cd -...ls...echo /
Il supprime le plus à gauche de ls
la sortie de pour contenir entièrement le nom du lien et la chaîne ->
. Bien que j'aie d'abord essayé d'éviter de le faire shift
et $IFS
il s'avère que c'est la méthode la plus fiable aussi proche que possible. C'est la même chose que le pauvre_man_readlink de Gilles - et c'est bien fait.
Il répétera ce processus en boucle jusqu'à ce que le nom de fichier renvoyé ne ls
soit définitivement pas un lien logiciel. À ce stade, il canonise ce chemin comme précédemment avec cd
puis imprime.
Exemple d'utilisation:
zpath \
/tmp/script \ #symlink to $HOME/test/dir/script.sh
ln \ #symlink to ./dir/
ln/nl \ #symlink to ../..
/dev/fd/0 \ #currently a here-document like : dash <<\HD
/dev/fd/1 \ #(zlink) | dash
file \ #regular file
doesntexist \ #doesnt exist
/dev/disk/by-path/pci-0000:00:16.2-usb-0:3:1.0-scsi-0:0:0:0 \
/dev/./././././././null \
. ..
SORTIE
/home/mikeserv/test/dir/script.sh
/home/mikeserv/test/dir/
/home/mikeserv/test/
/tmp/zshtpKRVx (deleted)
/proc/17420/fd/pipe:[1782312]
/home/mikeserv/test/file
ERR: NO_SUCH_PATH: doesntexist
/dev/sdd
/dev/null
/home/mikeserv/test/
/home/mikeserv/
Ou peut-être ...
ls
dir/ file file? folder/ link@ ln@ script* script3@ script4@
zdlm=\\0 zpath * | cat -A
SORTIE
/home/mikeserv/test/dir/^@$
/home/mikeserv/test/file^@$
/home/mikeserv/test/file$
^@$
/home/mikeserv/test/folder/^@$
/home/mikeserv/test/file$ #'link' -> 'file\n'
^@$
/home/mikeserv/test/dir/^@$ #'ln' -> './dir'
/home/mikeserv/test/script^@$
/home/mikeserv/test/dir/script.sh^@$ #'script3' -> './dir/script.sh'
/home/mikeserv/test/dir/script.sh^@$ #'script4' -> '/tmp/script' -> ...