À 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 cdla spécification de
Si l' -Poption est en vigueur, la $PWDvariable 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 $PWDvariable 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' pwdutilitaire 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 -Pdoit définir le répertoire de travail en cours sur ce qui pwd -Pdevrait autrement être imprimé et qui cd -doit imprimer le $OLDPWDque 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. cddéfinit $PWDdès que je suis cd -P . $PWDmaintenant 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à $HOMEdans un shell interactif quand cdest 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 $0le chemin d'accès de, mais dans le cas qui $0est 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 lset 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 unsetcertaines 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 stderrpourquoi 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 $_zdlmvariable (qui est également unsetaffiché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 $OLDPWDqu'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' cdentrer $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 $1existe 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 $1s'agit d'un lien symbolique qui ne pointe pas vers un répertoire. Dans ce cas, il appelle la whileboucle 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 lsla 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 shiftet $IFSil 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 lssoit définitivement pas un lien logiciel. À ce stade, il canonise ce chemin comme précédemment avec cdpuis 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' -> ...