Como executar um comando com um diretório como argumento e, em seguida, cd para o mesmo? Eu recebo "nenhum arquivo ou diretório"

15

Eu gostaria de construir uma função curta para fazer o seguinte. Digamos que eu movo o arquivo 'file.tex' para o meu diretório de documentos:

mv file.tex ~/Documents

Em seguida, gostaria de acessar cdesse diretório:

cd ~/Documents

Eu gostaria de generalizar isso para qualquer diretório, para que eu possa fazer isso:

mv file.tex ~/Documents
follow

e faça com que o followcomando leia o destino do comando anterior e execute de acordo. Para um diretório simples, isso não economiza muito tempo, mas ao trabalhar com diretórios aninhados, seria tremendo poder usar apenas

mv file.tex ~/Documents/folder1/subfolder1
follow

Eu pensei que seria relativamente simples e que eu poderia fazer algo assim:

follow()
{
    place=`history 2 | sed -n '1p;1q' | rev | cut -d ' ' -f1 | rev`
    cd $place
}

mas isso não parece funcionar. Se eu ecoar $place, obtenho a string desejada (estou testando ~/Documents), mas o último comando retorna

No such file or directory

O diretório certamente existe. Estou perdida. Você poderia me ajudar?

Fogo
fonte
Gostaria de ressaltar que, se você não se importa file.texem manter o local original, os links simbólicos são uma alternativa muito boa, pois você só precisa vincular uma vez e, sempre, apontará para a versão mais recente.
Kroltan
5
Maneira mais fácil: digite cd alt + .para substituir o último token do comando anterior. Repita para voltar ainda mais na história dos tokens finais. (Eu digo token não arg, porque foo &agarra &como o token final.) Você pode usar um argumento numérico (com escape-3 alt +. Por exemplo).
22616 Peter Cordes
veja também mkdir cd combo
Christopher Bottoms

Respostas:

18

Em vez de definir uma função, você pode usar a variável $_, que é expandida para o último argumento do comando anterior por bash. Então use:

cd "$_"

após o mvcomando.

Você também pode usar a expansão do histórico:

cd !:$

Se você deve usar uma função:

follow () { cd "$_" ;}

$ follow () { cd "$_" ;}
$ mv foo.sh 'foo bar'
$ follow 
foo bar$ 

NB: Esta resposta está direcionada ao formato exato dos argumentos da linha de comando que você usou, pois estamos lidando com parâmetros posicionais. Para outros formatos mv -t foo bar.txt, por exemplo , você precisa incorporar verificações específicas antecipadamente, um wrapper seria apropriado então.

heemail
fonte
A expansão do seu histórico (cd!: $) Funciona perfeitamente. Obrigado. No entanto, o outro (cd "$ _") não: mv file.tex ~ / Downloads / cd "$ _" bash: cd: __bp_preexec_invoke_exec: Não existe esse arquivo ou diretório. Aceitarei com prazer sua resposta como totalmente correta e obrigado.
Fogo
Eu sempre digitei (um tanto desperdiçador) um cd !$ou outro cd $(dirname !$). Não sabia sobre a $_variável!
precisa saber é o seguinte
Agora, o que acontece se eu fizer em mv -t ~/Documents file.texvez de mv file.tex ~/Documents? Bottom line, eu não estou certo de que este é solúvel no caso geral ... uma função de invólucro em torno ou que reimplementa mvpoderia ser melhor ...
um CVn
@ MichaelKjörling Will não trabalho exemplo simply..this é apenas para cobrir o OP caso tem, não a borda (ou todos) casos ..
heemayl
Você não precisa do cólon; !$é equivalente !:$e mais rápido para digitar.
Curinga
14

Com as combinações de teclas padrão do bash, a combinação Alt.copia o último argumento da linha de comando anterior para a atual. Então, digitando

$ mv foo ~/some/long/path/
$ cd <Alt><.>

renderia

$ mv foo ~/some/long/path/
$ cd ~/some/long/path/

e seria ainda menos digitado que a palavra follow.

Para maior comodidade, a repetição da Alt.combinação percorrerá os últimos argumentos de todas as linhas de comando anteriores.

Adendo: O nome do comando bash correspondente a essa combinação de teclas é yank-last-argou insert-last-argument. Ele pode ser encontrado na página de manual do bash, em "Comandos para manipulação do histórico" ou no manual de referência do Bash, mais exaustivo .)

Dubu
fonte
1
Isso é esperto. Obrigado! Não fazia ideia de que isso existisse.
Fogo
@ Fire Adicionei referências para esses comandos, para que você possa encontrar muito mais combinações de teclas interessantes (e esquecê-las imediatamente, como sempre faço).
Dubu
1
Você também pode usar <esc>, em seguida, .para obter o mesmo resultado que <alt>+., este útil quando você tem capslock remapped para escapar :)
gnur
1
@gnur vi (m) usuário, suponho. ;-)
Dubu
6

Você está quase certamente enfrentando o problema de que a expansão til ocorre antes da expansão dos parâmetros, o que pode ser explicado por um exemplo sucinto:

$ cd ~kaz
kaz $ var='~kaz'
kaz $ echo $var
~kaz
kaz $ cd $kaz
bash: cd: ~kaz: No such file or directory

Isso pode ser resolvido com eval. De qualquer forma, você precisará eval, porque você está puxando comandos do histórico e eles podem conter expansões arbitrárias, como:

$ mv file.tex ~/Documents/$(compute_folder_name foo-param)/subfolder1
$ follow

(Há problemas, como o fato de que a reexpansão desses valores talvez não corresponda mais à expansão original que ocorreu. Suponha que compute_folder_nameseja uma função que incrementa alguma variável global.)

Kaz
fonte
4
Você não precisa eval. (Ever.) Mas boa localização sobre os problemas da sequência de expansão. Se você mencionar a maior conveniência da expansão do histórico para usar evalaqui, esta será a melhor resposta na minha opinião; nenhum dos outros realmente explica por que a solução do Pôster original falhou.
Curinga