rename
permite atribuir diretamente a $_
, o que é ideal para este problema.
Embora os argumentos do código passemos para o Perl rename
utilitário freqüentemente executa correspondência e substituição (com s/
), e é totalmente aceitável para levar este problema dessa forma , não há realmente necessidade disso em casos como este onde você não está realmente examinando ou reutilizando o texto do nomes de arquivos antigos. rename
permite que você escreva praticamente qualquer código Perl, e não precisa ser incorporado em s/
/e
. Sugiro usar um comando como este:
rename -n 'our $i; $_ = sprintf "AS%02d.txt", ++$i' *
Ou, se você sentir vontade de raspar alguns personagens:
rename -n '$_ = sprintf "AS%02d.txt", ++our$i' *
(Pode ser ainda mais curto, mas não sem sacrificar a clareza.)
Ambos os comandos fazem a mesma coisa. Cada um mostra quais operações de renomeação seriam realizadas. Depois de experimentar um e ficar satisfeito com os resultados, execute-o novamente sem a opção -n
. Conforme escrito, isso produzirá os nomes dos arquivos AS01.txt
, AS02.txt
, ... , AS10.txt
, AS11.txt
e assim por diante. Você pode modificá-los conforme necessário e, em seguida, remover apenas -n
quando gostar do que vê.
Se você quiser preencher uma largura maior que 2, substitua o 2
por um número maior. Por exemplo, se por algum motivo você quisesse nomes de arquivo como AS00000000000001.txt
, você substituiria %02d
por %014d
. Se você não quiser preenchimento algum - mesmo que isso faça seus arquivos aparecerem em ordem não numérica quando você os listar mais tarde! - então você pode substituir %02d
por apenas %d
.
Como isso funciona? Seu shell expande *
em uma lista de arquivos antes mesmo de executar o rename
comando. A lista é classificada lexicograficamente (por exemplo, alfabeticamente) de acordo com as configurações locais atuais. rename
recebe os nomes dos arquivos como argumentos da linha de comandos e os processa na ordem em que estão listados. A expressão ++$i
é avaliada como uma maior que o valor atual da variável $i
e também define a variável $i
para esse novo valor incrementado. Esse valor é passado para sprintf
, que formata e coloca dentro de outro texto . Este texto é atribuído diretamente à variável especial $_
, que contém o nome do arquivo. Como o rename
processa os arquivos na ordem em que são passados como argumentos, eles são numerados de acordo.
Você deve ter notado a semelhança com a resposta de Oli !
Ambos declaram e incrementam uma variável de contador, e ambos usam sprintf
essencialmente da mesma maneira para incorporar o valor daquele contador, preenchido à esquerda com zeros, no outro texto dos novos nomes de arquivos. (As informações em qualquer resposta sobre como preencher com zeros - e alterar a largura de preenchimento - também se aplicam igualmente a ambos.) A razão pela qual elas são tão semelhantes é que o método na resposta mais antiga está realmente fazendo exatamente isso 1 , mas com etapas extras que são úteis para muitos problemas, mas não são realmente necessárias para este.
Para comparação, aqui está o segundo comando dessa resposta se for modificado para usar o estilo que usei aqui (e para preencher uma largura de 2, como fiz aqui, em vez de 3):
rename -n 's/.+/our $i; sprintf "AS%02d.txt", ++$i/e' *
A parte entre s/.+/
e /e
nesse comando agora é igual à expressão que atribuo a $_
(ou seja, o código no lado direito do operador =
) no primeiro comando em esta resposta.
- O operador
s/
tenta corresponder ao texto (nomes de arquivos que o seu shell expandiu de *
e passadas como argumentos da linha de comando quando executou rename
) com uma expressão regular e executa a substituição. /
está sendo usado como um delimitador para separar as diferentes partes da expressão s
. A primeira parte, .+
, é a expressão regular; corresponde a qualquer 1 caractere ( .
) e faz isso uma ou mais vezes ( +
) . Como os nomes dos arquivos nunca estão vazios - eles sempre têm pelo menos um caractere - essa é uma maneira de corresponder a qualquer arquivo 1 .
- Em seguida, ele produz texto de cada correspondência - ou seja, de cada nome de arquivo inteiro - que consiste em
our $i; sprintf "AS%02d.txt", ++$i
. Isso produz o novo nome de arquivo.Normalmente, um usa s/
para produzir texto que seja (a) substituindo texto que corresponda apenas a parte do nome do arquivo, ou (b) baseado no texto correspondente de alguma forma (por exemplo, pode usar uma variável especial como $&
que se expande para a correspondência). Nesse caso, porém, o texto correspondente não está sendo usado.
- Normalmente, o texto substituído
our $i; sprintf "AS%02d.txt", ++$i
seria usado como um nome de arquivo, não executado como código. Mas o sinalizador /e
no final faz com que o texto seja tratado como código-fonte Perl e avaliado, e usa o valor produzido fazendo isso (nesse caso, o valor de retorno da função sprintf
incorporada do Perl) como novo nome de arquivo.
Embora eu ache que o método que mostrei aqui seja uma abordagem mais clara e simples para esse problema do que qualquer método que use s/
com /e
, é bom estar ciente dessa técnica , porque é bem adequado para uma série de outros problemas de renomeação de arquivos, onde todos ou parte dos nomes de arquivos originais são examinados e / ou retidos. Eu recomendo este post no blog por Oli (que também escreveu essa resposta ), que inclui alguns desses exemplos.
1 Tecnicamente, <<> existe uma diferença no comportamento dos comandos $_ =
e s/
/e
de comandos. Na expressão regular .+
, não é estritamente verdadeiro que .
corresponda a qualquer caractere, porque não corresponde a nova linha . Você provavelmente não deve usar nomes de arquivos com novas linhas neles, mas você pode, e ocasionalmente um arquivo é nomeado dessa maneira por acidente. Se você quiser, compare a saída de rename -n 'our $i; $_ = sprintf "AS%02d.txt", ++$i' $'foo\nbar'
com a de rename -n 's/.+/our $i; sprintf "AS%02d.txt", ++$i/e' $'foo\nbar'
. Para fazer com que .
corresponda a uma nova linha, use o s
flag, que fica no final (com e
). Ou seja, escreva /se
no final em vez de /e
.