Renomeia recursivamente arquivos e diretórios

6

Estou usando este comando para renomear arquivos:

for fname in *;
do
    mv "$fname" $(echo "$fname" | sha1sum | cut -f1 -d' ')
done

Mas só renomeia no diretório atual. Digamos que eu tenha muitos diretórios e cada diretório contenha alguns outros diretórios e a última árvore de diretórios contenha arquivos. Quero renomeá-los com caracteres aleatórios.

Eu acho que find . -type f deve funcionar e já tentei, mas ainda não recebi nenhum comando de trabalho.

    
por Najib-botak Chin 10.08.2011 / 04:56

4 respostas

7

Com a localização:

find . -type f -exec sh -c 'SHELL COMMAND' {} \;

Isso invoca SHELL COMMAND em cada arquivo encontrado, por sua vez; o nome do arquivo é "$0" . Assim:

find . -type f -exec sh -c '
    mv "$0" "${0%/*}/$(printf "%s\n" "${0##*/}" | sha1sum | cut -d" " -f1)"
' {} \;

(Observe o uso de printf em vez de echo , caso você tenha um arquivo chamado -e ou -n ou alguns outros casos problemáticos que echo manipula.)

Você pode tornar isso um pouco mais rápido chamando o shell em lotes.

find . -type f -exec sh -c 'for x; do
      mv "$x" "${x%/*}/$(printf "%s\n" "${x##*/}" | sha1sum | cut -d" " -f1)";
    done' _ {} +

No zsh, há uma maneira fácil de combinar todos os arquivos no diretório atual e em seus subdiretórios recursivamente. O . qualificador de glob restringe as correspondências a arquivos regulares e D inclui arquivos de ponto.

for x in **/*(.D); do mv …; done

No bash ≥4, você pode executar shopt -s globstar e usar **/* para corresponder todos os arquivos no diretório atual e em seus subdiretórios recursivamente. Você precisará filtrar arquivos regulares no loop.

shopt -s globstar; GLOBIGNORE=".:.."
for x in **/*; do if [[ -f $x ]]; then mv …; done
    
por 11.08.2011 / 00:25
2

Crie um script auxiliar /tmp/tmp.sh:

#!/bin/bash
mv "$1" $(echo "$1" | sha1sum | cut -f1 -d' ')

torne-o executável e invoque-o:

find . -type f -execdir /tmp/tmp.sh {} ";"
    
por 10.08.2011 / 06:59
2

Se você está usando o Bash 4+, você pode fazer:

#!/bin/bash
shopt -s globstar
for fname in **/*; do 
  if [ -f "$fname" ]; then
    mv ...
  fi
done

Do Wiki do Bash Hacker:

There's a new shell option globstar. When enabled, Bash will perform recursive globbing on ** – this means it matches all directories and files from the current position in the filesystem, rather that only the current level.

link

    
por 10.08.2011 / 05:13
1

Isso lida com todos os espaços em branco ok ...

set -f; IFS= 
while read -r -d $'
set -f; IFS= 
while read -r -d $'%pre%' fname ;do
    mv ...
done < <(find . -type f -name '*' -print0)
set +f; IFS=$' \t\n' # you don't have to reset unless it effects subsequent code
' fname ;do mv ... done < <(find . -type f -name '*' -print0) set +f; IFS=$' \t\n' # you don't have to reset unless it effects subsequent code
    
por 10.08.2011 / 20:54

Tags