Como renomear arquivos em lote em um terminal macOS?

123

Eu tenho uma pasta com uma série de arquivos denominados:

prefix_1234_567.png
prefix_abcd_efg.png

Gostaria de remover em lote um sublinhado e o conteúdo do meio para que a saída fosse:

prefix_567.png
prefix_efg.png

Relevante, mas não completamente explicativo:

seqüestrar
fonte
veja os métodos de faixa e substring de NSString e NSMutableString
Grady Player
1
Você já considerou soluções não terminais para isso? Um fluxo de trabalho do Automator pode executar esses tipos de operações com facilidade. Você pode criar um fluxo de trabalho do automatizador para renomear todos os arquivos e substituir o texto _*_por um espaço em branco.
Encryptic
eu pensei automator não podia fazer wildcards
kidnim

Respostas:

234

No seu caso específico, você pode usar o seguinte bashcomando ( bashé o shell padrão no macOS):

for f in *.png; do echo mv "$f" "${f/_*_/_}"; done

Nota: Se houver uma chance de os nomes dos seus arquivos começarem -, coloque -- diante deles [1]:
mv -- "$f" "${f/_*_/_}"

Nota: echoé anexado a mvpara executar uma execução a seco. Remova-o para executar a renomeação real.

Você pode executá-lo na linha de comando ou usá-lo em um script.

  • "${f/_*_/_}"é uma aplicação de bash expansão de parâmetro : o (primeiro) padrão de correspondência de substring _*_é substituído por literal _, cortando efetivamente o token do meio do nome.
  • Observe que _*_é um padrão (uma expressão curinga, também usada para globbing), não uma expressão regular (para aprender sobre padrões, executar man bashe procurar Pattern Matching).

Se você renomear arquivos em lote com frequência, considere instalar uma ferramenta especializada, como o renameutilitário baseado em Perl . No macOS, você pode instalá-lo usando o popular gerenciador de pacotes Homebrew , da seguinte maneira:

brew install rename

Aqui está o equivalente ao comando no topo usando rename:

rename -n -e 's/_.*_/_/'  *.png

Novamente, este comando executa uma execução a seco; remove -npara executar a renomeação real.

  • Semelhante à bashsolução, s/.../.../executa a substituição de texto, mas - ao contrário de bash- expressões regulares verdadeiras são usadas.

[1] A finalidade do argumento especial --, que é apoiado pela maioria dos serviços públicos, é para sinalizar que os argumentos subsequentes devem ser tratados como operandos (valores), mesmo se eles olham como opções devido a começar -, como Jacob C. notas.

mklement0
fonte
3
ótima resposta, funcionou perfeitamente. Também aprecio o fato de que você voltou e o editou para explicar mais e fornecer uma solução mais elegante se eu repetir isso. mais uma vez, muito obrigado, muito útil
kidnim
4
Um exemplo usando substituições correspondentes ( .*-> $1), por exemplo, Renomear Foo bar S01E01 biz baz.extpara S01E01.ext:rename -n -e 's/.*(S[0-9]{2}E[0-9]{2}).*(\.[a-z]{2,4})/$1$2/' *
Steve Robbins
2
Adoro a idéia de usar echopara corridas a seco. Obrigado pela dica!
James Wright
Recomendo apenas fazer obrew install rename
Chris Redford
98

Para renomear arquivos, você pode usar o renameutilitário:

brew install rename

Por exemplo, para alterar uma sequência de pesquisa em todos os nomes de arquivos no diretório atual:

rename -nvs searchword replaceword *

Remova o parâmetro 'n' para aplicar as alterações.

Mais informações: man rename

David Thomas
fonte
1
OS XAs versões do GNU bash( x86_64-apple-darwin ) não incluem o utilitário de renomeação.
1
4
Obrigado, sim, precisa ser instalado viabrew install rename
David Thomas
2
Essa dica é demais! Digitei rename -vs GLYCOPHORIN GLYCC *e agora renomeia automaticamente mais de 450 arquivos. E super rápido também.
Sander W. van der Laan
3
Excelente! Adoro a parte "mostrar o que seria alterado" ANTES de realmente renomear as coisas!
Ben Duffin
3
Você pode usar uma regex também. renomear 's / 123 / onetwothree / g' *
Bryan
12

Você poderia usar sed:

ls * | sed -e 'p;s@_.*_@_@g' | xargs -n2 mv

resultado:

prefix_567.png prefix_efg.png

* para executar um teste a seco primeiro, substitua mvno final porecho

Explicação:

  • e: opcional para apenas 1 comando sed.
  • p: para imprimir a entrada para sed, nesse caso, será o nome do arquivo original antes de qualquer renomeação
  • @: é uma substituição do caractere / para tornar o sed mais legível. Ou seja, em vez de usar sed s / search / replace / g, use s @ search @ replace @ g
  • _. *: o sublinhado é um caractere de escape para se referir ao '.' real caractere zero ou mais vezes (em oposição a QUALQUER caractere na expressão regular)
  • -n2: indica que existem 2 saídas que precisam ser passadas para mv como parâmetros. para cada entrada de ls , este comando sed gerará 2 saídas, que serão fornecidas ao mv.
eu vou
fonte
1
Solução inteligente, embora um tanto misteriosa. Tornando isso mais geral, de modo a também apoiar nomes de arquivos com espaços incorporados, fica ainda mais misterioso: ls * | xargs -I % bash -c 'echo mv "%" "$(sed 's@_.*_@_@' <<<"%")"'(remova echopara realmente renomear).
usar o seguinte comando
2
Arcano? Eu amo isto!
precisa
7

Eu tinha um lote de arquivos parecido com este: be90-01.png e precisava alterar o traço para sublinhado. Eu usei isso, que funcionou bem:

for f in *; do mv "$f" "`echo $f | tr '-' '_'`"; done
JanB
fonte
2

você pode instalar o renamecomando usando brew. basta fazer brew install renamee usar.

Nisim Joseph
fonte
1

Usando mmv

mmv '*_*_*' '#1_#3' *.png
αғsнιη
fonte
você precisa instalar primeiro sudo apt-get install mmv.
αғsнιη
1
Dado que este era o OS X, o procedimento de instalação correto é brew install mmv.
buckaroo1177125
1

tente isso

for i in *.png ; do mv "$i" "${i/remove_me*.png/.png}" ; done

Aqui está outra maneira:

for file in Name*.png; do mv "$file" "01_$file"; done
Joolah
fonte