Qu'est-ce qu'un moyen portable pour un script (zsh) de déterminer son chemin absolu?
Sous Linux, j'utilise quelque chose comme
mypath=$(readlink -f $0)
... mais ce n'est pas portable. (Par exemple, readlink
sur darwin ne reconnaît pas le -f
drapeau, ni n'a d'équivalent.) (En outre, en utilisantreadlink
pour cela est, certes, un hack d'aspect assez obscur.)
Qu'est-ce qui est plus portable?
Réponses:
Avec
zsh
, c'est juste:Maintenant , pour d' autres coquilles, bien
realpath()
etreadlink()
sont des fonctions standard (ce dernier étant un appel système),realpath
etreadlink
ne sont pas commande standard, bien que certains systèmes ont l' un ou l'autre ou les deux avec différents comportements et fonctionnalités.Comme souvent, pour la portabilité, vous voudrez peut-être recourir à
perl
:Cela se comporterait plus comme GNU
readlink -f
querealpath()
(GNUreadlink -e
) dans la mesure où il ne se plaindra pas si le fichier n'existe pas tant que son nom de répertoire existe.la source
.zshrc
: consultez plutôt cet article .Dans zsh, vous pouvez effectuer les opérations suivantes:
Ou, pour obtenir le répertoire dans lequel réside le script:
Source: page de manuel zshexpn (1), section EXPANSION D'HISTOIRE, sous-section Modificateurs (ou simplement
info -f zsh -n Modifiers
).la source
readlink -f
serait plutôt$0:A
.J'utilise cela depuis plusieurs années maintenant:
la source
readlink -f
c'est quand le script lui-même est un lien symbolique.zsh
, si j'exécute cela directement ou dans le sous-shell (comme suggéré) dans mon répertoire personnel (/home/ville
), il s'imprime/home/ville/zsh
.Cette syntaxe doit être portable à un interprète de style Bourne shell (testé avec
bash
,ksh88
,ksh93
,zsh
,mksh
,dash
etbusybox sh
):Cette version ajoute la compatibilité au shell AT&T Bourne hérité (non POSIX):
la source
$PWD
peut être exagéré - vous pouvez simplement le régler sur un courant absolu commecd -P .
. Je doute que cela fonctionnerait en bourneshell - mais cela devrait fonctionner dans tous ceux que vous avez testés pour la première fois. fait pour moi de toute façon.zsh
etdirname
mais retirer rapidement Hir / son commentaire ...En supposant que vous vouliez vraiment dire le chemin absolu, c'est-à-dire un chemin depuis le répertoire racine:
Cela fonctionne d'ailleurs dans n'importe quel shell de style Bourne.
Si vous vouliez dire un chemin avec tous les liens symboliques résolus, c'est une autre affaire.
readlink -f
fonctionne sur Linux (à l'exception de certains systèmes BusyBox allégés), FreeBSD, NetBSD, OpenBSD et Cygwin, mais pas sur OS / X, AIX, HP / UX ou Solaris. Si c'est le casreadlink
, vous pouvez l'appeler en boucle:Si vous n'en avez pas
readlink
, vous pouvez l'approcher avecls -n
, mais cela ne fonctionne que sils
ne modifie aucun caractère non imprimable dans le nom de fichier.(L'extra
z
est dans le cas où la cible du lien se termine par une nouvelle ligne, ce que la substitution de commande mangerait autrement. Larealpath
fonction ne gère pas ce cas pour les noms de répertoire, soit dit en passant.)la source
ls
implémentation qui modifie les caractères non imprimables lorsque la sortie ne va pas à un terminal.touch Stéphane; LC_ALL=C busybox ls Stéphane | cat
→St??phane
(c'est si le nom est en UTF-8, latin1 vous en donne un?
). Je pense que je l'ai vu aussi sur les Unices commerciaux plus anciens.busybox
-ce que c'est? selon gitbusybox ls
n'a pas eu de changement de code depuis 2011. Monbusybox ls
- vers 2013 - ne fait pas cette chose. Celui- ci - vers 2012 - le fait . Cela pourrait expliquer pourquoi. Avez-vous construit votrebusybox
support avec Unicode - pour inclure le support wchar? Vous voudrez peut-être essayer, sinon vérifier les options de construction dans lemkinitcpio
busybox
package.À 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 deEt sur
pwd -P
C'est parce que
cd -P
doit définir le répertoire de travail en cours sur ce quipwd -P
devrait autrement être imprimé et quicd -
doit imprimer le$OLDPWD
que cela fonctionne:SORTIE
attendez ...
SORTIE
Et quand
cd -
j'imprime avec j'imprime$OLDPWD
.cd
définit$PWD
dès que je suiscd -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 quandcd
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:
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 alorsunset
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 pourstderr
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 égalementunset
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 versstdout
. 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 lawhile
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: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 faireshift
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 aveccd
puis imprime.Exemple d'utilisation:
SORTIE
Ou peut-être ...
SORTIE
la source
que diriez-vous d'un one-liner sympathique quand theres python disponible pour empêcher de redéfinir un algorithme?
identique à /programming//a/7305217
la source