![Busque todos os nomes de arquivos com um número específico de caracteres](https://rvso.com/image/109243/Busque%20todos%20os%20nomes%20de%20arquivos%20com%20um%20n%C3%BAmero%20espec%C3%ADfico%20de%20caracteres.png)
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 regX
no 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
- Os padrões globbing não suportam modificadores que dizem "repita as N vezes anteriores".
- 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 echo
quando 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 -f
teste, 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 arquivoecho
é para simulação, remova quando tudo estiver bem
Responder3
Se você tiver perl-rename (chamado rename
em sistemas baseados em Debian, perl-rename
em outros), você pode fazer:
perl-rename -n 's/^[0-9a-z]{16}$/$&.txt/' *
Se isso acontecer, remova o -n
para 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á from
por to
. Neste from
caso, é 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"
' {} {} \;