2010-09-08 60 views
45

Tengo una carpeta con aproximadamente 1.700 archivos. Todos son nombrados como 1.txt o 1497.txt, etc. Me gustaría cambiar el nombre de todos los archivos para que todos los nombres de los archivos tengan cuatro dígitos.Script de shell de Linux para agregar ceros a nombres de archivo

Es decir, 23.txt se convierte en 0023.txt.

¿Qué es un script de shell que hará esto? O una pregunta relacionada: ¿Cómo uso grep para que coincida solo con las líneas que contienen \d.txt (es decir, un dígito, luego un punto y luego las letras txt)?

Esto es lo que tengo hasta ahora:

for a in [command i need help with] 
do 
    mv $a 000$a 
done 

Básicamente, ejecute dicho tres veces, con comandos allí para encontrar un dígito, dos dígitos, y tres nombres de archivo dígitos (con el número de ceros iniciales cambiado).

+1

Usted debe etiquetar este con la cáscara está utilizando – meagar

+0

duplicado posible de [script de Bash para rellenar los nombres de los archivos] (http://stackoverflow.com/questions/55754/bash-script-to-pad-file-names) –

+1

@CiroSantilli, por cierto, tuve a alguien recientemente empujar a un engañado que se cerró con eso como la lógica para rellenar los números principales y la lógica para rellenar los números más adelante en un nombre difiere un tanto. (En consecuencia, https://stackoverflow.com/questions/46993470/padding-filenames-with-zeros-in-bash está actualmente marcado como una víctima de esta respuesta, y * no * un engañado de eso). –

Respuesta

46

Probar:

for a in [0-9]*.txt; do 
    mv $a `printf %04d.%s ${a%.*} ${a##*.}` 
done 

cambiar el patrón de nombre de archivo ([0-9]*.txt) según sea necesario.


Un propósito general de cambio de nombre enumerado que no hace suposiciones sobre el conjunto inicial de los nombres de archivo:

X=1; 
for i in *.txt; do 
    mv $i $(printf %04d.%s ${X%.*} ${i##*.}) 
    let X="$X+1" 
done 

Sobre el mismo tema:

+0

Esto produce un montón de errores para cada nombre de archivo que ya tiene 4 dígitos. Agregar el foo al principio solucionaría esto, pero no quería eso allí. Gracias por esos enlaces. –

+0

Lo siento por el "foo" ... Copiar/pegar mal –

0

única para que coincida con los archivos de texto de un solo dígito, que puede hacer ...

$ ls | grep '[0-9]\.txt' 
+0

¿Hay alguna manera de eliminar el '.txt' de $ a? Me he preguntado esto varias veces antes. –

+0

Sí, '$ {a% .txt}' hará eso (o '$ {a%. *}' Para eliminar cualquier sufijo). –

+0

Una forma rápida si conoce la extensión anterior es canalizar la salida a través de sed, así: 'ls | grep '[0-9] \. txt' | sed 's/\. txt // g'' – LukeN

11
for a in *.txt; do 
    b=$(printf %04d.txt ${a%.txt}) 
    if [ $a != $b ]; then 
    mv $a $b 
    fi 
done 
+0

¡Gracias por la respuesta! Básicamente lo mismo que el otro que llegó exactamente al mismo tiempo. –

+1

@David: Mi solución no causa muchos errores. :-P –

+0

No causa errores ** si ** los nombres de los archivos de entrada no tienen espacios. Probablemente debería agregar más citas para evitar eso. :) –

7

de una sola línea:

ls | awk '/^([0-9]+)\.txt$/ { printf("%s %04d.txt\n", $0, $1) }' | xargs -n2 mv 

¿Cómo se utiliza grep para las líneas de solape sólo que contienen \ d.txt (es decir, 1 dígito, luego de un período, entonces el letras txt)?

grep -E '^[0-9]\.txt$' 
12

Usando el guión rename (prename en algunos casos) que a veces se instala con Perl, puede utilizar expresiones Perl para hacer el cambio de nombre. El script omite el cambio de nombre si hay una colisión de nombre.

El siguiente comando cambia el nombre de los archivos que tienen cuatro o menos dígitos seguidos por una extensión ".txt". No cambia el nombre de los archivos que no se ajustan estrictamente a ese patrón. No trunca nombres que constan de más de cuatro dígitos.

rename 'unless (/0+[0-9]{4}.txt/) {s/^([0-9]{1,3}\.txt)$/000$1/g;s/0*([0-9]{4}\..*)/$1/}' * 

Unos pocos ejemplos:

Original Becomes 
1.txt  0001.txt 
02.txt  0002.txt 
123.txt  0123.txt 
00000.txt 00000.txt 
1.23.txt 1.23.txt 

Otras respuestas dadas hasta ahora intentará cambiar el nombre de los archivos que no se ajustan al patrón, producir errores de nombres de archivo que contienen caracteres que no sean dígitos, realizar cambios de nombre que producen colisiones de nombres, intente y no cambie el nombre de los archivos que tienen espacios en sus nombres y posiblemente otros problemas.

+0

Yagni. Seriamente. ¿A quién le importan los nombres de archivos que contienen espacios o caracteres no numéricos si eso no está dentro del alcance de la pregunta? Si el OP quería escribir un guión de uso general, lo habría dicho en la pregunta, y las respuestas se habrían acomodado en consecuencia. –

+13

@Chris: mis respuestas a menudo hacen dos cosas. Primero, intentan responder la pregunta de un OP.Dos, intentan proporcionar información adicional que puede ser útil para los futuros televidentes de la pregunta. –

+2

@Dennis: Gracias por brindarme esto, la respuesta mejor calificada no resolvió mi problema en particular, pero como notó, proporcionó una respuesta más general y más amplia que ayudó. Gracias. –

4

Supongamos que tiene archivos con datatype .dat en su carpeta. Sólo tienes que copiar este código a un archivo llamado run.sh, hacerlo ejecutable mediante la ejecución de chmode +x run.sh y luego ejecutar utilizando ./run.sh:

#!/bin/bash 
num=0 
for i in *.dat 
do 

    a=`printf "%05d" $num` 
    mv "$i" "filename_$a.dat" 
    let "num = $(($num + 1))" 
done 

Esto convertirá todos los archivos en la carpeta de filename_00000.dat, filename_00001.dat, etc.

0

Sugerencia de una línea:

while [ -f ./result/result`printf "%03d" $a`.txt ]; do a=$((a+1));done 
RESULT=result/result`printf "%03d" $a`.txt 
1

Esta versión también admite la gestión de cadenas antes (después) del número. Pero básicamente puedes hacer cualquier coincidencia de expresión regular + printf, siempre y cuando tu awk lo soporte. Y admite caracteres en espacios en blanco (excepto líneas nuevas) también en nombres de archivos.

for f in *.txt ;do 
    mv "$f" "$( 
     awk -v f="$f" '{ 
      if (match(f, /^([a-zA-Z_-]*)([0-9]+)(\..+)/, a)) { 
       printf("%s%04d%s", a[1], a[2], a[3]) 
      } else { 
       print(f) 
      } 
     }' <<<'' 
    )" 
done 
+0

Acabo de probar lo anterior y destruyó todos los archivos en el directorio y dejó un solo archivo "0000". – Ryan

+0

@Ryan Eso significa que la expresión regular no coincide con ningún archivo en su directorio. Tienes que personalizar el regex + printf para hacer cualquier cosa. El fragmento de arriba es solo un ejemplo. – rindeal

+0

rindeal es correcto. Cuando corregí la expresión regular para mis nombres de archivo (la mía tenía espacios) funcionó. Los nombres de archivo que no coinciden con la expresión regular aún se mueven a '0000', lo que tal vez sea un poco sorprendente. Si está haciendo un cambio de nombre masivo y va a probar scripts aleatorios que encuentre en SO, es mejor que tenga una copia de seguridad. – Ryan

0

para proporcionar una solución que ha cautela escrito para ser correcta, incluso en presencia de nombres de archivo con espacios:

#!/usr/bin/env bash 

pattern='%04d' # pad with four digits: change this to taste 

# enable extglob syntax: +([[:digit:]]) means "one or more digits" 
# enable the nullglob flag: If no matches exist, a glob returns nothing (not itself). 
shopt -s extglob nullglob 

for f in [[:digit:]]*; do    # iterate over filenames that start with digits 
    suffix=${f##+([[:digit:]])}   # find the suffix (everything after the last digit) 
    number=${f%"$suffix"}     # find the number (everything before the suffix) 
    printf -v new "$pattern" "$number" "$suffix" # pad the number, then append the suffix 
    if [[ $f != "$new" ]]; then     # if the result differs from the old name 
    mv -- "$f" "$new"       # ...then rename the file. 
    fi 
done 
Cuestiones relacionadas