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 popdno 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 popdsolo 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!)

trapcontrolador 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, unacshcaracterística copiada porbashyzsh, 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/dirseguido 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
~/xo~user/xnotación).Entonces, si la pila tiene actualmente
/ay/b, el directorio actual es/herey está ejecutando:pushdse imprimirá/tmp/whatever /here /a /bypopdsaldrá/here /a /b, no/tmp/whatever. Eso es independiente de usar la sustitución de comandos o no.popdno se puede usar para obtener la ruta del directorio anterior y, en general, su salida no se puede procesar posteriormente (consulte la matriz$dirstacko$DIRSTACKde 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 ejecutapushden una subshell. Si lo hizo, no podría cambiar el directorio de trabajo. Eso semktempejecuta 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
mktempen 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 usarzshfunciones anónimas:fuente
pushdypopdtrabajo 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)hacepopdque 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 depopdno 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 bashde punta a punta!Puede desvincular el directorio primero, antes de abandonarlo:
o
pero tenga en cuenta que
pushdypopdrealmente 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,
dirsproporcione una lista de directorios recordados por el método pushd / popd.Además,
dirs -1imprime el último directorio incluido en la lista.Entonces, para eliminar el directorio creado previamente mediante la ejecución
pushd $(mktmp -d), use:Y luego,
popdel directorio ya eliminado de la lista:Todo en una linea:
Y agregando la opción (-l) para evitar la notación
~/xo~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
rmdirya que es elpwden ese punto. Y se desvinculará después delpopdcomando (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
rmdirel directorio actual que es donde estarías al hacer esto. Necesita realizar elpopdantes de hacer elrmdirpero necesita saber qué eliminar ypopdno le dice eso. Yo, como tú, pensé quedirs -l -1era 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 quepushdmueve el pwd. Entonces, sí, despuéspushdy antes de popd, el directorio creado se almacena$(dirs -1), no veo ningún problema.