Arquivo Linux mv com nome longo


19

No Linux, às vezes, renomeio arquivos como este:

mv dir1/dir2/dir3/file.txt  dir1/dir2/dir3/file.txt.old

Observe que eu quero apenas renomear o arquivo, não movê-lo para outro diretório.

Existe um comando que me permita executar uma versão abreviada desse comando? Estou pensando em algo como:

mv dir1/dir2/dir3/file.txt  file.txt.old

ou talvez até algo como (para adicionar apenas ao nome):

mv dir1/dir2/dir3/file.txt  {}.old

Meu objetivo não é ter que especificar o caminho completo novamente.

Sei que esses "exemplos" que escrevi não funcionam, mas é apenas uma idéia do que quero realizar.

Eu não quero ter que entrar no diretório.


8
Por que você não muda para o diretório? É rápido e resolve o seu problema.
Michael Hampton

Estou lidando com muitos subdiretórios a partir deste mesmo local, é mais lento se eu tiver que voltar a este dir pai cada vez
santiago Arizti

3
Ninguém disse que você tinha que mudar para outro diretório, apenas o que você deseja.
Michael Hampton

Observe que ele (cd dir1/dir2/dir3 && exec mv file.txt{,.old})tem efetivamente o mesmo desempenho que o código sem o subprocesso, porque isso execevita fork()a chamada de comando externo; portanto, você tem exatamente uma bifurcação de qualquer maneira.
Charles Duffy

Respostas:


45

para um único arquivo, tente

mv dir1/dir2/dir3/file.{txt,txt.old}

para onde a X{a,b}construção se expande Xa Xb, você pode ter uma visualização usando

echo dir1/dir2/dir3/file.{txt,txt.old}

para ver se ele se encaixa na sua necessidade.

Nota:

  1. isso para vários arquivos

    mv dir1/dir2/dir3/file{1,2,3}.{txt,txt.old}
    

é improvável que se expanda para o que você deseja. (isso será expandido para uma mistura de file.txt file1.txt.old file2.txt ...)

  1. {txt,txt.old}pode ser limitado a {,.old}como por comentário

  2. se o nome do diretório não for ambíguo, o curinga poderá ser usado.

    mv *1/*2/d*/*.{,old}
    

para uso de vários arquivos rename

rename -n s/txt/old.txt/ dir1/dir2/dir3/file*.txt 

solte -npara ter renomeação efetiva.


1
legal, eu não conhecia esse jeito de expandir! obrigado
santiago arizti

14
Será que mv dir1/dir2/dir3/file.txt{,.old}também não funcionam, e ser ainda mais curto?
Josh

3
@ Josh Sim, funciona perfeitamente e requer menos pressionamentos de tecla. Eu uso esse construto muito regularmente.
Rlf

2
é engraçado como você pode usar o shell do Linux por anos e ainda encontrar novos truques o tempo todo
santiago arizti

Eu acho que todos esses "truques" seriam mais óbvios se eu tivesse algum treinamento formal na linguagem bash, mas eu estava apenas aprendendo o suficiente para me dar bem.
santiago arizti 21/01

6

O comando renamerenomeia todos os arquivos correspondentes. Seu principal objetivo é renomear vários arquivos, mas se a expressão Perl corresponder a apenas um arquivo, renomeará apenas esse único arquivo. Para obter detalhes e sintaxe específica distro por favor leia a página de manual: man rename.

Exemplo de uso: renomeie "/path/file.txt" para "/path/file.txt.old":

rename 's/file.txt/file.txt.old/g' /path/file.txt

Notação mais curta (graças a shalomb):

rename 's/$/.old/' /path/file.txt
rename '$_.=".old"' /path/file.txt

Para uso a seco rename -n.

Mais exemplos e detalhes podem ser encontrados em https://thepcspy.com/read/bulk-rename-files-in-ubuntu/


legal, eu sabia sobre o comando renomear, mas nunca soube tudo o que podia fazer, obrigado!
santiago Arizti

6
Infelizmente, diferentes distribuições Linux têm renamecomandos diferentes com um comportamento completamente diferente.
kasperd

1
Para esta tarefa específica de renomear anexando .oldao nome do arquivo, provavelmente é um pouco mais conveniente fazer um rename 's/$/.old/' /path/to/file.txtourename '$_.=".old"' /path/to/file.txt
shalomb

@Fabian - Eu não estava criticando, apenas apontando para o "lado mais curto" para o que parece ser um usado com freqüência idioma do OP está procurando :)
shalomb

4

Para um caso pontual, se eu não quiser alterar meu diretório atual, posso apenas usar um sub-shell:

(cd dir1/dir2/dir3/ && mv file.txt file.txt.old)

Como você está cddentro do sub-shell, não alterou seu diretório no seu shell real


4
Mais rápido e seguro de usar && exec mv- dessa forma, você não tenta renomear se cdfalhar e oexec consome o subshell, evitando assim uma penalidade no desempenho.
Charles Duffy

Concordo com o && Para um caso pontual, como eu disse, não me preocuparia com o custo do sub-shell (mantenha-o simples: ser capaz de lembrar facilmente como fazê-lo é mais importante da IMO)
Adam

Eu diria que, se você se lembrar apenas de uma maneira, lembrar da maneira eficiente ajuda a garantir que você não siga a rota ineficiente nos casos em que isso importa.
Charles Duffy

4

Gosto da solução da @ archemar de usar a expansão {}, porque você pode usá-la quando já tiver iniciado sua linha de comando. Aqui estão algumas outras possibilidades de completude:

F="dir1/dir2/dir3/file.txt" ; mv "$F" "$F.old"

(aspas são necessárias apenas se você tiver espaços ou outros caracteres de quebra de palavras no nome)

mymv() {
    mv "$1/$2" "$1/$3"
}

mymv dir1/dir2/dir3 file.txt file.txt.old
mymv dir5/dir6/dir7 file.txt file.txt.old

Notas:

  • Esta é a sintaxe do bash, você pode estar usando outro shell
  • mymv pode ser qualquer string razoável, usei mymv para "minha jogada".
  • A definição da função pode ser colocada no seu .bash_profile

Outro:

cd dir1/dir2/dir3 ; mv file.txt file.txt.old ; cd -

mas

(cd dir1/dir2/dir3/ && exec mv file.txt file.txt.old)

(de @Adam e @CharlesDuffy) é sem dúvida melhor no caso de o CD falhar.


1
Não use mmv, já existe um programa chamado dessa maneira.
glglgl

1
@glglgl Feito :)
Law29

2

Se você deseja entrar no subdiretório para diminuir o mv comando, mas deseja retornar ao diretório atual posteriormente, há duas maneiras de fazer isso. Uma é colocar o cde mvem um subshell (como já foi sugerido).

O outro é usar pushde popdalterar diretórios:

pushd dir1/dir2/dir3/; mv file.txt file.txt.old; popd

O pushdcomando é como cd, exceto que ele primeiro coloca o nome do diretório atual em uma pilha. popdremove o nome do topo da pilha e muda para esse diretório.


pushde popdsão extensões destinadas ao uso interativo - o POSIX as lista explicitamente como "os resultados não são especificados" e um shell criado para a execução de scripts (por exemplo, em um ambiente incorporado mínimo) não precisa de suporte.
Charles Duffy

2

Eu apenas faria

cd dir1/dir2/dir3/
mv file.txt file.txt.old
cd ~- # go to the most recent directory

0

A solução envolvendo: mv something{.txt,.txt.old}está usando um "basismo". Se você deseja uma maneira mais portátil, usando manipulações de variáveis ​​comuns:

# rename all files "file*.txt" of directory /dir1/dir2/dir3 into file*.txt.old:
for f in dir1/dir2/dir3/file*.txt ; do
  mv "$f" "${f/.txt/.txt.old}"  # note there are no terminating "/"
done


# "${var/A/B}" is the content of var with the first occurence of "A" replaced by "B"

2
Veja pubs.opengroup.org/onlinepubs/009695399/utilities/… para a especificação POSIX pertinente - ${var/text/replacement}é um próprio basismo.
Charles Duffy

@CharlesDuffy oh ... Você me deixa triste :(
Olivier Dulac
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.