Renomeia recursivamente arquivos de e-mail de .txt para .eml

2

O diretório "$ d" contém alguns milhares de arquivos de e-mail com a extensão .txt. Para abri-los no meu cliente de e-mail, preciso renomeá-los para .eml

Este comando irá renomeá-los corretamente:

find "${d}" -type f -name '*.txt' | while read f; do mv -vn "${f}" "${f%.*}".eml; done

ou existe uma maneira melhor e mais robusta de fazer isso?

Eu não conseguia pensar em uma maneira elegante de fazer isso usando:

-exec ...{}... \;
    
por Robottinosino 11.06.2012 / 19:38

4 respostas

5

Sua solução é geralmente boa, mas vai quebrar em novas linhas. Aqui está uma solução bash4 + um pouco mais robusta:

shopt -s globstar nullglob
for file in **/*.txt; do
    mv "$file" "${file%.*}.eml"
done
    
por 11.06.2012 / 21:42
1

Eu acho que você deve estar bem com

find "$d" -name \*.txt -exec rename .txt .eml {} \;

ou até mesmo

for f in *.txt; do rename .txt .eml "$f"; done

se todos os arquivos estiverem no mesmo diretório.

    
por 11.06.2012 / 20:00
0

Sim, seu comando funcionará, supondo que você esteja usando bash ou um shell com sintaxe semelhante. No futuro, quando estiver contemplando um comando grande como esse, lembre-se de que você pode usar echo para visualizar as linhas de comando resultantes. Ou seja você pode colocar echo na frente de mv , executar o pipeline e ver quais serão os comandos. Se eles parecem OK, remova echo e execute o comando para real.

    
por 11.06.2012 / 20:04
0

Em zsh, zmv torna isso fácil. Coloque autoload -U zmv no seu ~/.zshrc e, em seguida, use uma das várias maneiras de especificar um texto de substituição para **/*.txt que corresponda aos arquivos com a extensão txt no diretório atual e nos subdiretórios:

zmv '**/*.txt' '$f:r.eml'
zmv '**/*.txt' '${f%.*}.eml'
zmv '(**/)(*).txt' '$1$2.eml'
zmv -w '**/*.txt' '$1$2.eml'

Se você não tem zsh, mas tem bash ≥4 ou ksh93, você pode usar o ** para percorrer subdiretórios recursivamente e, em seguida, percorrer as correspondências. Você precisará ativar o padrão ** glob primeiro com shopt -s globstar no bash (coloque em ~/.bashrc ) ou set -o globstar no ksh (coloque em ~/.kshrc ). Isso também funciona em zsh (sem configuração prévia necessária).

for f in **/*.txt; do mv -- "$f" "${f%.*}.eml"; done

Observe que isso renomeia todos os arquivos, não apenas arquivos regulares. Se você tiver diretórios ou outros arquivos não regulares e quiser deixá-los intocados:

zmv -Q '**/*.txt(.)' '$f:r.eml'
for f in **/*.txt; do [[ -f $f ]] && mv -- "$f" "${f%.*}.eml"; done

Sem recurso de shell além de POSIX, você precisará invocar find para percorrer subdiretórios. Sua solução é frágil porque quebra arquivos contendo barras invertidas, espaços em branco ou linhas novas. Você pode corrigir o espaço em branco à direita e a barra invertida com while IFS= read -r f; do … , mas canalizando a saída de find inerentemente quebra em novas linhas. Use -exec em vez disso. No Linux, você pode usar o utilitário rename ( qualquer que seja sua distribuição ). No Debian, Ubuntu e derivados:

rename 's/\.txt$/.eml/' **/*.txt
find . -name '*.txt' -type f -exec rename 's/\.txt$/.eml/' {} +

Em outras distribuições, desde que nenhum dos nomes de arquivo contenha .txt no meio (porque rename substitui a primeira ocorrência da string de origem):

rename .txt .eml **/*.txt
find . -name '*.txt' -type f -exec rename .txt .eml {} +

Com apenas recursos POSIX, invoque um shell para executar a transformação no nome.

find . -name '*.txt' -type f -exec sh -c 'for f; do mv "$f" "${f%.*}.eml"; done' _ {} +

Se o find for muito antigo para suportar -exec … + , será necessário invocar um shell por arquivo, o que torna o código mais simples, mas mais lento.

find . -name '*.txt' -type f -exec sh -c 'mv "$0" "${0%.*}.eml"; done' {} \;
    
por 10.06.2013 / 12:26

Tags