Como executo comandos em outra pasta, sem repetir o caminho da pasta?

73

Existe uma maneira inteligente de copiar e mover operações ou um comando para duplicar um arquivo, sem ter que fazer um cde mvdepois na mesma pasta?

Por exemplo, eu tenho que executar o seguinte:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

Observe que o diretório para onde estou movendo o arquivo é o mesmo, mas tenho que colocar todo o caminho novamente e às vezes fica irritante. Estou curioso para saber se existe outra maneira de fazer isso sem ter que colocar o caminho inteiro novamente , porque a operação seria feita no mesmo caminho.

Valter Silva
fonte
9
Não acredito que isso tenha tantos votos positivos. É um unix.stackexchange.com/questions/35782/… duplicado e unix.stackexchange.com/questions/66889/…
user13107
13
@ user13107 Há muitas maneiras de fazer uma pergunta, incluindo palavras diferentes. E se você não souber que a resposta é chamada de "expansão de chave", talvez não seja possível encontrá-la imediatamente.
Slhck 17/05
2
@ user13107 eles estão em um site diferente, portanto não duplicados #
user151019 18/13/13
11
Mark, obrigado, eu não conhecia essa regra sobre duplicatas. @slhck Sim. Compreendo. Fiquei frustrado porque minha pergunta sobre o Unix.SE foi fechada como duplicada e essa ficou muito popular.
User13107 18/05
3
@ user13107, isso é o que você ganha para postar no site direita
Samuel Edwin Ward

Respostas:

125

Basta usar a expansão de chaves :

mv /folder1/folder2/folder3/{file.txt,file-2013.txt}

Isso é equivalente a escrever:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

A expansão de chaves permite fornecer mais argumentos, é claro. Você pode até passar intervalos para que, por exemplo, para criar um par de pastas de teste, você pode executar mkdir test_{a..z}, e começando com Bash 4, você pode criar seqüências com zeros à esquerda, bem como, como em touch foo{0001..3}, o que cria foo0001, foo0002e foo0003. O Bash Hackers Wiki tem um artigo com alguns exemplos para você.

Se você precisar usar dois comandos diferentes, use um subshell e cd, primeiro, como na resposta de @ Ignacio .

slhck
fonte
5
Não sabia da braceexpansão, obrigado!
Valter Silva 17/05
Eu tentei e parece não funcionar:meniac ~: mv /tmp/f1/f2/f3/f4/f5/f6/{file.txt, file2.txt} mv: cannot stat ``/tmp/f1/f2/f3/f4/f5/f6/{file.txt,': No such file or directory
Valter Silva 17/05
5
Você tem certeza de que está usando o Bash, como em /bin/bash, e não está em um script que possui /bin/sho shebang ou algum outro shell que não suporta expansão de chaves? Se você executar set, o seu SHELLOPTScontém braceexpand?
Slhck 17/05
22
Observe que não deve haver espaço entre file.txt,e file2.txt.
Slhck 17/05
9
Você pode torná-lo ainda mais curto, para evitar erros de digitação na parte que não mudam:mv /folder1/folder2/folder3/file{,-2013}.txt
Jan Fabry
74

Execute a operação em um subshell.

( cd /folder1/folder2/folder3 && mv file.txt file-2013.txt )

A alteração do diretório de trabalho não será propagada para o shell pai.

Ignacio Vazquez-Abrams
fonte
11
+1: Eu gosto que um, mais conchas em todo portátil do que o truque cinta-expansão (o que é puro, mas menos portátil)
Olivier Dulac
@ Olivier, o que faz você pensar que a expansão da cinta não é portátil? Qual shell você tem em mente que não o suporta?
Alexis
5
A expansão @alexis Brace não é especificada pelo POSIX, portanto não é portátil "por design". ash, dash, ksh88Para não mencionar o antigo shell Bourne são exemplo de conchas não apoiá-lo.
Jlliagre
@jlliagre Quais das conchas que você mencionou estão totalmente em conformidade com o POSIX? Isso significa que eles não teriam suporte à expansão, mesmo que fosse POSIX. O ksh88 foi anterior à ratificação do POSIX; você deve atualizar para pelo menos ksh93. Os únicos dois que alguém no Linux se importaria são o ash e o dash, pois são usados ​​em algumas pequenas distribuições incorporadas (busybox, iirc?) E discos de resgate.
Kaz
2
@ Kaz Eu me preocupo com a portabilidade dos comandos do shell e o fato de serem interativos ou não, não importa. Obviamente, você é livre para não se importar com isso, mas aceite que as pessoas pensam o contrário. O fato de você sempre usar o bash ou um shell que suporta expansão de barce não significa que esse é o caso de todos.
Jlliagre
21

Se você quiser inteligência, aqui está a expansão do histórico do bash

mv /folder1/folder2/folder3/file.txt !#:1:h/file-2013.txt

Eu não usaria isso sozinho, pois acho impossível memorizar. Ocasionalmente, uso o equivalente ao vim , mas tenho que procurá-lo quase todas as vezes.

Glenn Jackman
fonte
11

Você pode definir uma variável. Claro que isso tem o efeito colateral de deixar as variáveis ​​por aí.

D=/folder1/folder2/folder3; mv $D/file.txt $D/file-2013.txt
sjbotha
fonte
E, é claro, você pode evitar o efeito colateral de deixar as variáveis ​​por aí, colocando toda a linha de comando em um subshell:, (D="/folder1/folder2/folder3"; mv "$D"/file.txt "$D"/file-2013.txt)ou simplesmente adicionando um unsetcomando no final. (Adicionei aspas como uma “melhor prática”; se você costuma usar aspas, não precisará parar e coçar a cabeça quando aparecer um nome de caminho que contenha caracteres especiais.)
Scott
@ Scott, se você usar um subshell para eliminar efeitos colaterais, é mais fácil fazer um cddo que definir uma variável. Não é muito mais fácil, eu admito.
Isaac Rabinovitch
2

Eu gosto das outras soluções, mas aqui está outra, implementada como um script com matrizes bash, pushd, popd:

#!/bin/bash
set -e
# from http://stackoverflow.com/a/246128/178651
script_path="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# paths relative to the script
relative_paths=( \
path1 \
path2 \
path3 \
path4
)

for relative_path in "${relative_paths[@]}"
do
  pushd "$script_path/$relative_path" > /dev/null 2>&1
  pwd
  mv filename1 filename2
  # could do other stuff in this directory...
  popd > /dev/null 2>&1
done

pushd "$script_path" > /dev/null 2>&1
# could do other stuff in same directory as script...
popd > /dev/null 2>&1
Gary S. Weaver
fonte
1

Slhck responde diretamente à pergunta da maneira mais simples possível, mas Valter também gosta da resposta de autopop, então aqui está uma que segue a mesma linha;

pushd /folder1/folder2/folder3/; mv file.txt file-2013.txt; popd
Isaac Rabinovitch
fonte