J'ai un scénario qui appelle à la substitution de commandes sans utiliser de sous-shell. J'ai une construction comme celle-ci:
pushd $(mktemp -d)
Maintenant, je veux quitter et supprimer le répertoire temporaire en une seule fois:
rmdir $(popd)
Cependant, cela ne fonctionne pas car popd
ne renvoie pas le répertoire popped (il retourne le nouveau répertoire, maintenant actuel) et aussi parce qu'il est effectué dans un sous-shell.
Quelque chose comme
dirs -l -1 ; popd &> /dev/null
retournera le répertoire popped mais il ne peut pas être utilisé comme ceci:
rmdir $(dirs -l -1 ; popd &> /dev/null)
car popd
cela n'affectera que le sous-shell. Ce qu'il faut, c'est la capacité de le faire:
rmdir { dirs -l -1 ; popd &> /dev/null; }
mais c'est une syntaxe invalide. Est-il possible d'obtenir cet effet?
(note: je sais que je peux enregistrer le répertoire temporaire dans une variable; j'essayais d'éviter de le faire et d'apprendre quelque chose de nouveau dans le processus!)
trap
gestionnaire peut nettoyer le répertoire si le processus est poussé par un signal.fish
, l'équivalent de la substitution de commandes()
, change le dossier du shell externe. C'est généralement ennuyeux, mais dans des cas comme celui-ci, c'est utile, j'en suis sûr.Réponses:
Le choix du titre de votre question est un peu déroutant.
pushd
/popd
, unecsh
fonctionnalité copiée parbash
etzsh
, est un moyen de gérer une pile de répertoires mémorisés.pousse le répertoire de travail en cours sur une pile, puis modifie le répertoire de travail en cours (puis imprime
/some/dir
suivi du contenu de cette pile (séparé par des espaces).imprime le contenu de la pile (là encore, séparé par des espaces), puis passe à l'élément supérieur de la pile et le fait disparaître de la pile.
(attention également à ce que certains répertoires y seront représentés avec leur notation
~/x
ou~user/x
).Donc, si la pile contient actuellement
/a
et/b
, le répertoire actuel est/here
et vous exécutez:pushd
imprimera/tmp/whatever /here /a /b
etpopd
sortira/here /a /b
, non/tmp/whatever
. C'est indépendant de l'utilisation de la substitution de commandes ou non.popd
ne peut pas être utilisé pour obtenir le chemin du répertoire précédent, et en général, sa sortie ne peut pas être post-traitée (voir le tableau$dirstack
ou$DIRSTACK
de certains shells pour accéder aux éléments de cette pile de répertoires)Peut-être que vous voulez:
Ou
Cependant, j'utiliserais:
Dans tous les cas,
pushd "$(mktemp -d)"
ne s'exécute paspushd
en sous-shell. Si tel était le cas, il ne pourrait pas modifier le répertoire de travail. Voilàmktemp
qui fonctionne en sous-coquille. Comme il s'agit d'une commande distincte, elle doit s'exécuter dans un processus distinct. Il écrit sa sortie sur un tuyau et le processus shell la lit à l'autre extrémité du tuyau.ksh93 peut éviter le processus séparé lorsque la commande est intégrée, mais même là, c'est toujours un sous-shell (un environnement de travail différent) qui cette fois est émulé plutôt que de s'appuyer sur l'environnement séparé normalement fourni par la fourche. Par exemple, dans
ksh93
,a=0; echo "$(a=1; echo test)"; echo "$a"
, aucune fourchette est impliquée, mais encoreecho "$a"
sorties0
.Ici, si vous voulez stocker la sortie de
mktemp
dans une variable, en même temps que vous la passez àpushd
, aveczsh
, vous pouvez faire:Avec d'autres coques de type Bourne:
Ou pour utiliser
$(mktemp -d)
plusieurs fois la sortie sans la stocker explicitement dans une variable, vous pouvez utiliserzsh
des fonctions anonymes:la source
pushd
etpopd
travaille comme vous le décrivez et qu'ils sont indépendants de la substitution de commande - pas de confusion là-bas! Cependant, vous avez répondu par votre propre problème en révélant$OLDPWD
. Je peux fairepopd; rmdir $OLDPWD
. C'est la réponse à mon problème - tout le reste confirme simplement ce que je pensais. La substitution de commandes semble être un moyen de le résoudre, mais ce n'est pas à cause du sous-shell et vous ne pouvez pas faire de substitution de commandes sans sous-shell, alors merci d'avoir révélé OLDPWD - c'est exactement ce dont j'ai besoin!rmdir $(popd)
faitpopd
tourner dans un sous-shell ce qui signifie qu'il ne changera pas le répertoire courant, mais même s'il ne s'est pas exécuté dans un sous-shell, la sortie depopd
ne sera pas le répertoire temporaire, ce sera une liste séparée par des espaces des répertoires n'incluant pas ce répertoire temporaire. C'est là que je dis que vous êtes confus.OLDPWD
. Je dois penser à lire un jourman bash
de bout en bout!Vous pouvez d'abord dissocier le répertoire avant de le quitter:
ou
mais notez que
pushd
etpopd
sont vraiment des outils pour les shells interactifs, pas pour les scripts (c'est pourquoi ils sont si bavards; les vraies commandes de script sont silencieuses quand elles réussissent).la source
En bash,
dirs
fournissez une liste des répertoires mémorisés par la méthode pushd / popd.Imprime également
dirs -1
le dernier répertoire inclus dans la liste.Donc, pour supprimer le répertoire créé précédemment en exécutant
pushd $(mktmp -d)
, utilisez:Et puis,
popd
le répertoire déjà supprimé de la liste:Tout en une ligne:
Et en ajoutant l'option (-l) pour éviter la notation
~/x
ou~user/x
:Ce qui est remarquablement similaire à la ligne que vous avez demandée.
Sauf que je ne l'utiliserais pas
&>
car cela cacherait tout rapport d'erreur depopd
.Remarque: le répertoire restera après
rmdir
tel qu'il estpwd
à ce point. Et sera effectivement dissocié après lapopd
commande (aucun lien restant utilisé).Il existe une option à utiliser, pour les shells qui supportent la variable "OLDPWD" (la plupart des shells de type bourne: ksh, bash, zsh have
$OLDPWD
). Il est intéressant de noter que ksh n'implémente pas les répertoires, pod, pushd par défaut (lksh, dash et autres n'ont pas non plus de popd disponibles, donc ne sont pas utilisables ici):Ou, plus idiomatique (même liste de coques que ci-dessus):
la source
rmdir
le répertoire actuel qui est où vous seriez lorsque vous faites cela. Vous devez effectuer lepopd
avant de faire lermdir
mais vous devez savoir quoi supprimer etpopd
ne vous le dit pas. Comme vous, je pensais quedirs -l -1
c'était la réponse, mais j'ai découvert depuis que la réponse est en fait à utiliser$OLDPWD
.popd && rmdir ~-
.rmdir "$PWD"
bien. De plus, le répertoire courant doit être celui créé parmktmp -d
(s'il apushd $(mktemp -d)
été exécuté au préalable) et vers lequelpushd
se déplace le pwd. Donc, oui, aprèspushd
et avant popd, le répertoire créé est stocké dans$(dirs -1)
, je ne vois aucun problème.