
Então, digamos, eu tenho um diretório com vários arquivos como g.txt, onde g.txt foi modificado pela última vez em, digamos, 20 de junho de 2012.
Como eu renomearia em lote todos os arquivos (como g.txt) com a data da última modificação de 20 de junho de 2012 anexada no final?
Responder1
aqui está uma versão da frase de goldschrafe que:
não usa estatísticas
funciona com versões anteriores do GNU date
lida corretamente com quaisquer espaços nos nomes dos arquivos
também lida com nomes de arquivos começando com um travessão
for f in *; do mv -- "$f" "$f-$(date -r "$f" +%Y%m%d)"; done
Atualização 2021-03-20
Minha resposta a esta pergunta tem me incomodado há anos (bem, apenas quando me lembro dela - em dias como hoje, quando recebe outro voto positivo), então estou finalmente atualizando-a. Minha resposta original acima ainda funciona, mas a resposta atualizada abaixo é melhor.
Comoqualqueroperação de renomeação de arquivo em lote, isso deve ser feito com operl rename
utilitário, não com algum shell desajeitado para loop.
O utilitário de renomeação perl é efetivamente uma linguagem de script especializada que permite usar QUALQUER código perl para renomear arquivos, desde s/search/replace/
operações simples de expressão regular (que são suficientes para a maioria das tarefas de renomeação) até scripts complexos de várias linhas.
por exemplo
rename -n 'BEGIN {use Date::Format};
die $! unless -f $_;
next if (m/-\d{8}$/);
my $ts=(stat($_))[9];
my $dt=time2str("%Y%m%d",$ts);
s/$/-$dt/;' *.txt
Isso requer apenas perl e o Date::Format
módulo (um módulo que é tão útil que deve ser instalado em qualquer sistema com perl. IMO, junto com o Date::Parse
módulo do autor Graham Barr,devefaz parte da biblioteca de módulos principais do perl, mas não é, então você terá que instalá-lo com cpan
um pacote de distribuição como libtimedate-perl
o pacote do Debian).
Aliás, este script ignora qualquer arquivo que pareça já ter uma data (ou seja, 8 dígitos) no final do nome do arquivo.
ou, para uma versão mais sofisticada que coloca a data antes do sufixo do arquivo (se houver):
rename -n 'BEGIN {use Date::Format; use File::Basename};
die $! unless -f $_;
my ($filename,$dirs,$suffix) = fileparse($_,qr/\.[^.]*/);
next if (m/-\d{8}${suffix}$/);
my $ts=(stat($_))[9];
my $dt=time2str("%Y%m%d",$ts);
s/${suffix}$/-${dt}${suffix}/;' *.txt
Esta versão não tem requisitos extras porque o File::Basename
módulo foi incluído como um módulo principal padrão com perl desde que me lembro (pelo menos uma década, provavelmente mais).
Observação:ambos rename
os scripts acima usam a opção "dry-run" do rename -n
(também conhecido como --nono
) para que os resultados possam ser testados/simulados antes de serem aplicados. Remova -n
(ou substitua-o -v
por saída detalhada) quando tiver certeza de que ele faz o que deseja.
Observe também:como acontece com qualquer outro rename
script perl, isso pode renomear nomes de arquivos fornecidos na linha de comando e/ou na entrada padrão. por exemplo, para renomear todos os arquivos .txt no diretório atual e em todos os subdiretórios:
find . -type f -iname '*.txt' -print0 |
rename -0 --nofullpath -n '..........'
A propósito, usei a opção rename
--nofullpath (também conhecida como -d
, --filenmame
, --nopath
) aqui para garantir que ela renomeie apenas a parte do nome do arquivo de qualquer caminho de arquivo encontrado. Não é necessário neste caso em particular (porque os scripts de renomeação de exemplo apenas alteram o final do nome do arquivo), mas geralmente é uma boa ideia quando você não deseja renomear o caminho e também o nome do arquivo (por exemplo, um script de renomeação como 's/ //g'
remover espaços dos nomes de arquivos tentariam remover quaisquer espaços no caminho, bem como o nome do arquivo sem --nofullpath
, provavelmente causando falha com um erro).
Finalmente:não confunda o script perl rename (também conhecido como File::Rename
, ou às vezes chamado prename
no Fedora & RedHat, ou perl-rename
) com qualquer outro programa chamado rename. Apenaseste utilitário de renomeação baseado em Perl pode renomear arquivos usando código Perl arbitrário, conforme mostrado acima, qualquer outro utilitário de renomeação terá recursos diferentes e opções de linha de comando diferentes e incompatíveis.
Você pode verificar se possui a renomeação correta instalada:
$ rename -V
/usr/bin/rename using File::Rename version 1.13, File::Rename::Options version 1.10
O executável pode ser chamado prename
ou perl-rename
ou file-rename
no seu sistema, então tente -V
com eles e ajuste os exemplos acima para usar o nome correto do executável.
Responder2
One-liner Bash rápido e sujo para renomear todos os arquivos (globbed) no diretório atual de filename.txt
para filename.txt-20120620
:
for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done
Um nerd empreendedor do Bash encontrará algum caso extremo para quebrá-lo, tenho certeza. :)
Obviamente, isso não faz coisas desejáveis, como verificar se um arquivo já possui algo parecido com uma data no final.
Responder3
One-liner zsh obrigatório (sem contar o carregamento único de componentes opcionais):
zmodload zsh/stat
autoload -U zmv
zmv -n '(*)' '$1-$(stat -F %Y%m%d +mtime -- $1)'
Usamos o stat
embutido dozsh/stat
módulo, e azmv
função para renomear arquivos. E aqui está um extra que coloca a data antes da prorrogação, se houver.
zmv -n '(*)' '$1:r-$(stat -F %Y%m%d +mtime -- $1)${${1:e}:+.$1:e}'
Responder4
Aqui está a versão do one-liner do cas, (baseado no oneliner de goldschrafe) estendido comidempotência,
ou seja, estendido para arquivos de prefixo com data, hora efazer isso apenas para aqueles que ainda não possuem prefixo de data e hora.
Caso de uso: útil se você adicionar novos arquivos ao diretório e desejar adicionar prefixo de data e hora àqueles que ainda não possuem um.
for f in * ; do
if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
fi;
done