Busque todos os nomes de arquivos com um número específico de caracteres

Busque todos os nomes de arquivos com um número específico de caracteres

Quero alterar todos os nomes de arquivos, pois eles têm o comprimento exato de 16 caracteres (dígitos e letras minúsculas). Eu tentei [0-9a-z]{16}o [0-9a-z]\{16\}espaço reservado regXno trecho a seguir, mas não funcionou.

for file in <regX>
do
  mv "$file" "${file}.txt"
done

Responder1

Padrões de globulação de cascanão são expressões regulares. Eles podem parecer semelhantes, mas funcionam de maneira bastante diferente em alguns aspectos.

A expressão regular [0-9a-z]{16}corresponde a uma string que contém uma série de 16 caracteres do intervalo de caracteres mencionado (a string que contém a correspondência pode ser mais longa).

O padrão equivalente de shell globbing seria algo como

*[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]*

Isto é porque

  1. Os padrões globbing não suportam modificadores que dizem "repita as N vezes anteriores".
  2. Os padrões globbing são, por padrão, ancorados no início e no fim. É por isso que inseri *no início e no final do padrão. A *corresponde a qualquer número de qualquer caractere. Remova-os se quiser combinarexatamente16 caracteres.

Você pode criar uma string de 16 [0-9a-z]usando Perl:

$ pattern="$( perl -e 'print "[0-9a-z]" x 16' )"

Com bash, você pode optar por iterar todos os nomes no diretório atual e depois testar se os nomes correspondem à sua expressão regular:

for name in *; do
    if [[ -f "$name" ]] && [[ "$name" =~ ^[0-9a-z]{16}$ ]]; then
        echo mv "$name" "$name.txt"
    fi
done

Remova o echoquando você souber que está fazendo a coisa certa.

Observe que ancorei o padrão para que nomes mais longos não correspondam. Também estou me certificando, com o -fteste, de que os nomes que obtemos são, na verdade, apenas de arquivos normais.

Responder2

Comextglob

shopt -s extglob
for file in +([0-9a-z])
do
    [[ ${#file} == 16 ]] && echo mv "$file" "${file}.txt"
done
  • +([0-9a-z])significa um ou mais [0-9a-z]caracteres
  • ${#file}fornece o comprimento do nome do arquivo
  • echoé para simulação, remova quando tudo estiver bem

Responder3

Se você tiver perl-rename (chamado renameem sistemas baseados em Debian, perl-renameem outros), você pode fazer:

perl-rename -n 's/^[0-9a-z]{16}$/$&.txt/' *

Se isso acontecer, remova o -npara que ele realmente renomeie os arquivos. A sintaxe de perl-renameé um comando perl. Aqui, estamos usando o operador de substituição ( s/from/to/) que substituirá frompor to. Neste fromcaso, é o seu regex e toé a variável especial $&que significa "o que quer que tenha correspondido", mais a extensão .txt.


Para fazer isso com um shell glob (use@Kusalananda'sou@Sundeep'sabordagem, isso é apenas para fins de conclusão):

for f in [0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]; do
    mv -- "$f" "$f".txt
done

Com GNU find:

find . -regextype posix-extended -regex '.*/[0-9a-z]{16}' -exec mv {} {}".txt" \;

Responder4

L16=$(csh -c 'repeat 16 echo -n "?"')
find . -name "$L16" ! -name '*[!0-9a-z]*' -exec sh -c '
   mv "$1" "$1.txt"
' {} {} \;

informação relacionada