Eu tenho um cenário que exige substituição de comando sem usar um subshell. Eu tenho uma construção como esta:
pushd $(mktemp -d)
Agora eu quero sair e remover o diretório temporário de uma só vez:
rmdir $(popd)
No entanto, isso não funciona porque popd
não retorna o diretório pop-up (retorna o novo diretório, agora atual) e também porque é executado em uma subshell.
Algo como
dirs -l -1 ; popd &> /dev/null
retornará o diretório popped, mas ele não pode ser usado assim:
rmdir $(dirs -l -1 ; popd &> /dev/null)
porque popd
isso afetará apenas o subshell. O que é necessário é a capacidade de fazer isso:
rmdir { dirs -l -1 ; popd &> /dev/null; }
mas isso é sintaxe inválida. É possível alcançar esse efeito?
(nota: eu sei que posso salvar o diretório temporário em uma variável; estava tentando evitar a necessidade de fazer isso e aprender algo novo no processo!)
trap
manipulador pode limpar o diretório, caso o processo seja cutucado por um sinal.fish
, o equivalente à substituição de comando()
, altera a pasta do shell externo. Geralmente é irritante, mas em casos como esse é útil, tenho certeza.Respostas:
A escolha do título da sua pergunta é um pouco confusa.
pushd
/popd
, umcsh
recurso copiado porbash
ezsh
, é uma maneira de gerenciar uma pilha de diretórios lembrados.empurra o actual directório de trabalho para uma pilha, e , em seguida, modifica a pasta de trabalho actual (e, em seguida, imprime
/some/dir
seguido pelo teor de que a pilha (espaço-separadas).imprime o conteúdo da pilha (novamente, com espaço separado) e depois muda para o elemento superior da pilha e o remove da pilha.
(também tomar cuidado para que alguns diretórios será representado lá com sua
~/x
ou~user/x
notação).Portanto, se a pilha atualmente possui
/a
e/b
, o diretório atual é/here
e você está executando:pushd
imprimirá/tmp/whatever /here /a /b
epopd
produzirá/here /a /b
, não/tmp/whatever
. Isso é independente do uso de substituição de comando ou não.popd
não pode ser usado para obter o caminho do diretório anterior e, em geral, sua saída não pode ser pós-processada (consulte a$dirstack
ou a$DIRSTACK
matriz de alguns shells para acessar os elementos dessa pilha de diretórios)Talvez você queira:
Ou
Porém, eu usaria:
De qualquer forma,
pushd "$(mktemp -d)"
não é executadopushd
em um subshell. Caso isso acontecesse, não poderia alterar o diretório de trabalho. Isso émktemp
executado em um subshell. Por ser um comando separado, ele deve ser executado em um processo separado. Ele grava sua saída em um tubo, e o processo de shell a lê na outra extremidade do tubo.O ksh93 pode evitar o processo separado quando o comando é incorporado, mas mesmo assim, ainda é um subshell (um ambiente de trabalho diferente) que desta vez é emulado, em vez de depender do ambiente separado normalmente fornecido pelo bifurcação. Por exemplo, em
ksh93
,a=0; echo "$(a=1; echo test)"; echo "$a"
nenhum garfo está envolvido, mas aindaecho "$a"
gera saídas0
.Aqui, se você deseja armazenar a saída de
mktemp
uma variável, ao mesmo tempo em que a passa parapushd
, comzsh
, você pode:Com outras conchas do tipo Bourne:
Ou, para usar a saída
$(mktemp -d)
várias vezes sem armazená-la explicitamente em uma variável, você pode usarzsh
funções anônimas:fonte
pushd
epopd
trabalho como você descreve e que eles são independentes da substituição de comandos - não há confusão aí! No entanto, você respondeu por seu próprio problema, revelando$OLDPWD
. Eu posso fazerpopd; rmdir $OLDPWD
. Essa é a resposta para o meu problema - tudo o resto apenas confirma o que eu pensava. A substituição de comandos parece ser uma maneira de resolvê-lo, mas não é por causa do subshell e você não pode fazer a substituição de comandos sem um subshell. Então, obrigado por revelar o OLDPWD - é exatamente isso que eu preciso!rmdir $(popd)
fazpopd
com que seja executado em um sub-shell, o que significa que não mudará o diretório atual, mas mesmo que não tenha sido executado em um subshell, a saída depopd
não será o diretório temporário, será uma lista separada por espaço de diretórios que não incluem esse diretório temporário. É onde estou dizendo que você está confuso.OLDPWD
. Devo lembrar de um dia lerman bash
de ponta a ponta!Você pode desvincular o diretório primeiro, antes de deixá-lo:
ou
Mas note que
pushd
epopd
são realmente ferramentas para shells interativos, não para scripts (que é por isso que eles são tão falador; comandos reais de script são silenciosos quando conseguem).fonte
No bash,
dirs
forneça uma lista de diretórios lembrados pelo método pushd / popd.Além disso,
dirs -1
imprime o último diretório incluído na lista.Portanto, para remover o diretório criado anteriormente pela execução
pushd $(mktmp -d)
, use:E então,
popd
o diretório já removido da lista:Tudo em uma linha:
E adicionando a opção (-l) para evitar o
~/x
ou~user/x
notação:O que é notavelmente semelhante à linha que você solicitou.
Exceto que eu não usaria
&>
, pois ocultaria qualquer relatório de erro porpopd
.Nota: O diretório permanecerá depois do
rmdir
que estápwd
naquele ponto. E será realmente desvinculado após opopd
comando (nenhum link restante usado).Existe uma opção para usar, para shells que suportam a variável "OLDPWD" (a maioria dos shells semelhantes a bourne: ksh, bash, zsh have
$OLDPWD
). É interessante notar que o ksh não implementa dirs, pod, pushd por padrão (lksh, dash e outros também não possuem popd disponível, portanto, não são utilizáveis aqui):Ou, mais idiomático (mesma lista de conchas como acima):
fonte
rmdir
o diretório atual, onde você estaria ao fazer isso. Você precisa efetuar opopd
procedimento antes de fazer o procedimento,rmdir
mas precisa saber o que remover epopd
não diz isso. Eu, como você, pensei quedirs -l -1
era a resposta, mas descobri que a resposta é realmente usar$OLDPWD
.popd && rmdir ~-
.rmdir "$PWD"
tudo bem. Além disso, o diretório atual deve ser o criado pormktmp -d
(sepushd $(mktemp -d)
foi executado anteriormente) e para o qualpushd
move o pwd. Então, sim, depoispushd
e antes do popd, o diretório criado é armazenado$(dirs -1)
, não vejo nenhum problema.