Tengo un escenario que requiere la sustitución de comandos sin usar una subshell. Tengo una construcción como esta:
pushd $(mktemp -d)
Ahora quiero salir y eliminar el directorio temporal de una vez:
rmdir $(popd)
Sin embargo, eso no funciona porque popd
no devuelve el directorio emergente (devuelve el nuevo directorio, ahora actual) y también porque se realiza en una subshell.
Algo como
dirs -l -1 ; popd &> /dev/null
devolverá el directorio emergente pero no se puede usar así:
rmdir $(dirs -l -1 ; popd &> /dev/null)
porque popd
solo afectará a la subshell. Lo que se requiere es la capacidad de hacer esto:
rmdir { dirs -l -1 ; popd &> /dev/null; }
pero esa es una sintaxis inválida. ¿Es posible lograr este efecto?
(nota: ¡Sé que puedo guardar el directorio temporal en una variable; estaba tratando de evitar la necesidad de hacerlo y aprender algo nuevo en el proceso!)
trap
controlador puede limpiar el directorio en caso de que el proceso sea activado por una señal.fish
, el equivalente de la sustitución de comandos()
, cambia la carpeta del shell externo. Suele ser molesto, pero en casos como este es útil, estoy seguro.Respuestas:
La elección del título de su pregunta es un poco confusa.
pushd
/popd
, unacsh
característica copiada porbash
yzsh
, es una forma de administrar una pila de directorios recordados.empuja el directorio de trabajo actual a una pila y luego cambia el directorio de trabajo actual (y luego imprime
/some/dir
seguido por el contenido de esa pila (separados por espacios).imprime el contenido de la pila (de nuevo, separados por espacios) y luego cambia al elemento superior de la pila y lo saca de la pila.
(también tenga en cuenta que algunos directorios estarán representados allí con su
~/x
o~user/x
notación).Entonces, si la pila tiene actualmente
/a
y/b
, el directorio actual es/here
y está ejecutando:pushd
se imprimirá/tmp/whatever /here /a /b
ypopd
saldrá/here /a /b
, no/tmp/whatever
. Eso es independiente de usar la sustitución de comandos o no.popd
no se puede usar para obtener la ruta del directorio anterior y, en general, su salida no se puede procesar posteriormente (consulte la matriz$dirstack
o$DIRSTACK
de algunos shells para acceder a los elementos de esa pila de directorios)Quizás quieras:
O
Sin embargo, usaría:
En cualquier caso,
pushd "$(mktemp -d)"
no se ejecutapushd
en una subshell. Si lo hizo, no podría cambiar el directorio de trabajo. Eso semktemp
ejecuta en una subshell. Dado que es un comando separado, debe ejecutarse en un proceso separado. Escribe su salida en una tubería, y el proceso de shell lo lee en el otro extremo de la tubería.ksh93 puede evitar el proceso por separado cuando el comando está integrado, pero incluso allí, sigue siendo una subshell (un entorno de trabajo diferente) que esta vez se emula en lugar de depender del entorno separado que normalmente proporciona la bifurcación. Por ejemplo, en
ksh93
,a=0; echo "$(a=1; echo test)"; echo "$a"
no hay una bifurcación involucrada, pero aún seecho "$a"
emite0
.Aquí, si desea almacenar la salida
mktemp
en una variable, al mismo tiempo que se le pasa apushd
, conzsh
, usted podría hacer:Con otras conchas tipo Bourne:
O para usar la salida de
$(mktemp -d)
varias veces sin almacenarla explícitamente en una variable, puede usarzsh
funciones anónimas:fuente
pushd
ypopd
trabajo como lo describe y que son independientes de la sustitución de comandos, ¡no hay confusión! Sin embargo, respondiste por tu propio problema revelando$OLDPWD
. Que puedo hacerpopd; rmdir $OLDPWD
. Esa es la respuesta a mi problema: todo lo demás solo confirma lo que pensaba. La sustitución de comandos parece ser una forma de resolverlo, pero no se debe a la subshell y no se puede hacer la sustitución de comandos sin una subshell, así que gracias por revelar OLDPWD, ¡eso es exactamente lo que necesito!rmdir $(popd)
hacepopd
que se ejecute en un sub-shell, lo que significa que no cambiará el directorio actual, pero incluso si no se ejecutó en un subshell, la salida depopd
no será el directorio temporal, será una lista separada por espacios de directorios que no incluyen ese directorio temporal. Que es donde estoy diciendo que estás confundido.OLDPWD
. ¡Debo recordar leer un díaman bash
de punta a punta!Puede desvincular el directorio primero, antes de abandonarlo:
o
pero tenga en cuenta que
pushd
ypopd
realmente son herramientas para shells interactivos, no para scripts (es por eso que son tan habladores; los comandos de scripting reales son silenciosos cuando tienen éxito).fuente
En bash,
dirs
proporcione una lista de directorios recordados por el método pushd / popd.Además,
dirs -1
imprime el último directorio incluido en la lista.Entonces, para eliminar el directorio creado previamente mediante la ejecución
pushd $(mktmp -d)
, use:Y luego,
popd
el directorio ya eliminado de la lista:Todo en una linea:
Y agregando la opción (-l) para evitar la notación
~/x
o~user/x
:Lo cual es notablemente similar a la línea que solicitó.
Excepto que no lo usaría,
&>
ya que ocultaría cualquier informe de errorpopd
.Nota: El directorio permanecerá después
rmdir
ya que es elpwd
en ese punto. Y se desvinculará después delpopd
comando (no se utilizarán los enlaces restantes).Hay una opción para usar, para los shells que admiten la variable "OLDPWD" (la mayoría de los shells tipo bourne: ksh, bash, zsh have
$OLDPWD
). Es interesante notar que ksh no implementa directorios, pod, pushd por defecto (lksh, dash y otros tampoco tienen popd disponible, por lo tanto, no se pueden usar aquí):O, más idiomático (la misma lista de conchas que el anterior):
fuente
rmdir
el directorio actual que es donde estarías al hacer esto. Necesita realizar elpopd
antes de hacer elrmdir
pero necesita saber qué eliminar ypopd
no le dice eso. Yo, como tú, pensé quedirs -l -1
era la respuesta, pero desde entonces descubrí que la respuesta es realmente usar$OLDPWD
.popd && rmdir ~-
.rmdir "$PWD"
bien. Además, el directorio actual debe ser el creado pormktmp -d
(sipushd $(mktemp -d)
se ejecutó de antemano) y al quepushd
mueve el pwd. Entonces, sí, despuéspushd
y antes de popd, el directorio creado se almacena$(dirs -1)
, no veo ningún problema.