Preciso renomear aprox. 70.000 arquivos. Por exemplo: de sb_606_HBO_DPM_0089000
até sb_606_dpm_0089000
etc.
O intervalo de números vai de 0089000
a 0163022
. É apenas a primeira parte do nome que precisa mudar. todos os arquivos estão em um único diretório e são numerados sequencialmente (uma sequência de imagens). Os números devem permanecer inalterados.
Quando eu tento isso no bash, fico gritando que a "lista de argumentos é muito longa".
Editar:
Tentei renomear um único arquivo com mv
:
mv sb_606_HBO_DPM_0089000.dpx sb_606_dpm_0089000.dpx
Tentei renomear um intervalo (aprendi aqui na semana passada como mover uma carga de arquivos, então pensei que a mesma sintaxe poderia funcionar para renomear os arquivos ...). Eu acho que eu tentei o seguinte (ou algo parecido):
mv sb_606_HBO_DPM_0{089000..163023}.dpx sb_606_dpm_0{089000..163023}.dpx
ARG_MAX
limite do shell . Como essa pergunta solicita explicitamente uma solução de linha de comando, soluções GUI (possivelmente iguais), como na outra pergunta, também não coincidem.mv {1..2} {3..4}
que não funciona, o que é um problema totalmente diferente deARG_MAX
... Todos os outros que responderam provavelmente sentirão o mesmo! Então, do meu ponto de vista, eu gostaria que você reverter sua última edição e, se você quiser, fazer uma nova pergunta inteiro sobremv
ing com faixasargument list too long
erro. Não há necessidade de esclarecer mais, isso claramente não é uma bobagem, pois precisamos de uma solução alternativa para lidar com ARG_MAX e as respostas na duplicata proposta não fazem isso.Respostas:
Uma maneira é usar
find
com-exec
, e a+
opção Isso cria uma lista de argumentos, mas divide a lista em quantas chamadas forem necessárias para operar em todos os arquivos sem exceder a lista de argumentos máxima. É adequado quando todos os argumentos serão tratados da mesma maneira. Este é o caso comrename
, embora não commv
.Pode ser necessário instalar o Perl renomear:
Então você pode usar, por exemplo:
Remova
-n
após o teste, para realmente renomear os arquivos.fonte
Vou sugerir três alternativas. Cada um é um comando simples de linha única, mas fornecerei variantes para casos mais complicados, principalmente no caso de os arquivos a serem processados serem misturados com outros arquivos no mesmo diretório.
mmv
Eu usaria o comando mmv do pacote com o mesmo nome :
Observe que os argumentos são passados como seqüências de caracteres, para que a expansão glob não ocorra no shell. O comando recebe exatamente dois argumentos e localiza os arquivos correspondentes internamente, sem limites rígidos no número de arquivos. Observe também que o comando acima pressupõe que todos os arquivos que correspondem ao primeiro glob devem ser renomeados. Claro que você é livre para ser mais específico:
Se você tiver arquivos fora do intervalo de números solicitado no mesmo diretório, pode ser melhor usar os números de loop over dados mais abaixo nesta resposta. No entanto, você também pode usar uma sequência de invocações mmv com padrões adequados:
loop sobre números
Se você deseja evitar a instalação de qualquer coisa ou precisa selecionar por intervalo de números, evitando correspondências fora desse intervalo, e está preparado para aguardar 74.023 chamadas de comando, você pode usar um loop bash simples:
Isso funciona particularmente bem aqui, pois não há lacunas na sequência. Caso contrário, convém verificar se o arquivo de origem realmente existe.
Observe que, em contraste com
for ((i=89000; i<=163022; ++i))
a expansão da cinta, lida com zeros à esquerda, pois alguns Bash lançam alguns anos atrás. Na verdade, uma alteração solicitada, por isso estou feliz em ver casos de uso.Leitura adicional: Expanda a chave nas páginas de informações do Bash, principalmente na parte sobre
{x..y[..incr]}
.loop sobre arquivos
Outra opção seria fazer um loop sobre um globo adequado, em vez de apenas fazer um loop no intervalo inteiro em questão. Algo assim:
Novamente, essa é uma
mv
chamada por arquivo. E novamente o loop contém uma longa lista de elementos, mas a lista inteira não é passada como argumento para um subprocesso, mas manipulada internamente pelo bash, para que o limite não cause problemas.Leitura adicional: Expansão dos parâmetros do shell nas páginas de informações do Bash, documentando
${parameter/pattern/string}
entre outros.Se você deseja restringir o intervalo de números ao que você forneceu, adicione uma verificação para isso:
Aqui
${i##pattern}
remove a mais longa correspondência prefixopattern
de$i
. Esse prefixo mais longo é definido como qualquer coisa, depois um sublinhado e zero ou mais zeros. O último é escrito como*(0)
um padrão glob extendido que depende daextglob
opção que está sendo configurada. A remoção de zeros à esquerda é importante para tratar o número como base 10 e não 8. O+([0-9])
argumento no loop é outro globo estendido, que corresponde a um ou mais dígitos, apenas no caso de você ter arquivos que iniciam o mesmo, mas não terminam em um número.fonte
Uma maneira de contornar o
ARG_MAX
limite é usar o builtin do bash shellprintf
:Ex.
mas
fonte
find
no diretório atual.
para todos os arquivos-type f
e fazer mudar o nome do arquivo encontrado$1
com a substituiçãoHBO_DPM
comdmp
um por um-exec ... \;
substitua
echo
pormv
para renomear.fonte
Você pode escrever um pequeno script python, algo como:
Salve isso como um arquivo de texto, como
rename.py
na pasta em que os arquivos estão e, em seguida, com o terminal nessa pasta, vá:fonte
Você pode fazer arquivo por arquivo (pode levar algum tempo) com
Como o Perl
rename
usado em outras respostas,rename.ul
também tem uma opção-n
ou--no-act
para teste.fonte
-n
bandeira que eu usei para testar e sugerindo que ela também pode ser usadarename.ul
.Vejo que ninguém convidou meu melhor amigo
sed
para a festa :). O seguintefor
loop alcançará seu objetivo:Existem muitas ferramentas para esse trabalho, selecione a que for mais compreensível para você. Este é simples e facilmente alterado para se adequar a este ou a outros fins ...
fonte
$i
na substituição de comando, mas não há maneira fácil de lidar com uma nova linha à direita no nome do arquivo.Como estamos dando opções, aqui está uma abordagem Perl.
cd
no diretório de destino e execute:Explicação
perl -e
: Executar o script dada por-e
.foreach(glob){}
: execute o que estiver no{ }
resultado de cada glob.glob("sb_*")
: retorna uma lista de todos os arquivos e diretórios no diretório atual cujos nomes correspondem ao shell globsb*
.rename $_, s/_HBO_DPM_/_dpm_/r
: magia perl.$_
é uma variável especial que contém cada elemento sobre o qual estamos iterando (noforeach
). Então aqui, cada arquivo será encontrado.s/_HBO_DPM_/_dpm_/
substitui a primeira ocorrência de_HBO_DPM_
com_dpm_
. Como é executado$_
por padrão, é executado em cada nome de arquivo. Os/r
meios "aplicam essa substituição a uma cópia da sequência de destino (o nome do arquivo) e retornam a sequência modificada.rename
Faz o que você esperaria: renomeia arquivos. Portanto, a coisa toda renomeará o nome do arquivo atual ($_
) para si mesmo com_HBO_DPM_
substituído por_dpm_
.Você pode escrever a mesma coisa que um script expandido (e mais legível):
fonte
Dependendo do tipo de renomeação que você está visualizando, o uso do vidir com edição de várias linhas pode ser satisfatório.
No seu caso particular, você pode selecionar todas as linhas no seu editor de texto e remover a parte _ " HBO" dos nomes de arquivos com poucas teclas.
fonte
vidir
?