Renombrar archivos para agregar un sufijo

13

Necesito un comando para cambiar el nombre de todos los archivos en el directorio de trabajo actual, de manera que el nuevo nombre de archivo sea el mismo que el anterior, pero que incluya un sufijo correspondiente al número de líneas de los archivos originales (por ejemplo, si el archivo ftiene 10 líneas, entonces debe cambiarse el nombre a f_10).

Aquí está mi intento (que no funciona):

 linenum=$(wc -l); find * -type f | grep -v sh | rename 's/^/ec/'*
Martin Yeboah
fuente
¡Podrías hacer eso una respuesta! (Si agrega algo nuevo a las respuestas existentes, pero parece que sí)
Volker Siegel

Respuestas:

13

Qué tal si:

for f in *; do mv "$f" "$f"_$(wc -l < "$f"); done

Por ejemplo:

$ wc -l *
 10 file1
 40 file2
100 file3
$ ls
file1_10  file2_40  file3_100

Si desea mantener las extensiones (si están presentes), use esto en su lugar:

for f in *; do 
    ext=""; 
    [[ $f =~ \. ]] && ext="."${f#*.}; 
    mv "$f" "${f%%.*}"_$(wc -l < "$f")$ext; 
done
terdon
fuente
Gracias terdon! esta línea de comando parece hacer el trabajo, pero ¿cómo puedo cambiar el punto (.) a (_)? Además, como mi script está dentro de la carpeta, también cambia su nombre y, por lo tanto, permite que mi script se ejecute una vez (porque el nombre del script cambia ...)
Martin Yeboah
@MartinYeboah ver respuesta actualizada para el _. En cuanto al guión, ¿qué guión? Eso debe ejecutarse desde la línea de comandos, no hay necesidad de un script. Si solo desea que coincida con algunos archivos, cambie in *a, por ejemplo, in *txto algo así.
terdon
muchas gracias;) Olvidé totalmente que debería ejecutarse desde la línea de comando :)
Martin Yeboah
Creo que en wc -l < $flugar del grep sería más fácil de entender (y tal vez mejor para realizar, pero no lo he comprobado).
musiKk
@musiKk sí, pero como las otras respuestas están usando wc, quería mostrar un enfoque diferente. Pero está bien, lo suficientemente justo.
terdon
10

Puedes probar este liner:

find . -maxdepth 1 -type f -exec bash -c 'mv -i "$1" "$1.$(wc -l <"$1")"' _ {} \;
  • Esto encontrará todos los archivos en el directorio de trabajo actual ( find . -maxdepth 1 -type f)

  • Luego, estamos ejecutando una instancia de shell sobre los archivos encontrados para cambiar el nombre de los archivos para agregar el número de líneas.

Ejemplo:

$ ls
bar.txt spam.txt foo.txt

$ find . -maxdepth 1 -type f -exec bash -c 'mv -i "$1" "$1.$(wc -l <"$1")"' _ {} \;

$ ls
bar.txt.12 foo.txt.24 spam.txt.7
heemayl
fuente
6

Otra forma que conserva la extensión (si está presente) usando rename:

for f in *; do rename -n "s/([^.]+)(\.?.*)/\$1_$(< "$f" wc -l)\$2/" "$f"; done

Si el resultado es el esperado, elimine la -nopción:

for f in *; do rename "s/([^.]+)(\.?.*)/\$1_$(< "$f" wc -l)\$2/" "$f"; done
kos
fuente
renamegenial =) +1
AB
1
¿No fallaría esto en abcd? Cambie el segundo grupo de captura a (\.?[^\.]+).
ps95
@ prakharsingh95 eso es cierto, sin embargo (\.?[^\.]+), no es aceptable, ya sea porque va a coincidir sólo hasta el segundo punto y no coincidirá con un nombre de archivo con puntos consecutivos o terminando con un punto independientemente. No es una solución fácil, difícil, la única forma parece hacer dos sustituciones.
kos
@kos tienes razón. ¿Qué tal ([^ \.] +). *? ([^ \.] + $) No estoy seguro acerca de la optimización. Violín de
ps95
1
@ prakharsingh95 no desea escapar .clases de personajes en su interior.
terdon
5

Utilizando find:

find . -maxdepth 1 -type f -print0 | while read -d $'\0' f; do mv "$f" "$f"_$(grep -c . "$f"); done

Ejemplo

% wc -l *
  3 doit
  5 foo

% find . -maxdepth 1 -type f -print0 | while read -d $'\0' f; do mv "$f" "$f"_$(grep -c . "$f"); done

% wc -l *                         
  3 doit_3
  5 foo_5
AB
fuente
¿Por qué el -name "*"? ¿Restos de las pruebas? ;)
kos
1
@kos Viejo hábito: \
AB
3

Sólo por diversión y risitas con una solución rename. Dado que renamees una herramienta de Perl que acepta una cadena arbitraria que se evalúa, puede hacer todo tipo de travesuras. Una solución que parece funcionar es la siguiente:

rename 's/.*/open(my $f, "<", $_);my $c=()=<$f>;$_."_".$c/e' *
musiKk
fuente
Idea interesante +1
AB
2

El siguiente script cubre múltiples casos: el punto único y la extensión (file.txt), múltiples puntos y extensiones (file.1.txt), puntos consecutivos (file..foobar.txt) y puntos en el nombre del archivo (archivo. O archivo..).

La secuencia de comandos

#!/bin/bash
# Author: Serg Kolo
# Date:  June 25,2015
# Description: script to rename files to file_numlines
# written for http://askubuntu.com/q/640430/295286

# Where are the files ?
WORKINGDIR=/home/xieerqi/substitutions
# Where do you want them to go ?
OUTPUTDIR=/home/xieerqi/substitutions/output

for file in $WORKINGDIR/* ;do 
    FLAG=0
    EXT=$(printf "%s" "$file" | awk -F'.' '{printf "%s",$NF }' )  # extension, last field of dot-separated string
    # EXT="${file##*.}" # Helio's advice is to use parameter expansion, but I dont know how to use it
    if [ -z $EXT ]; then # we have a dot at the end case file. or something
        # so we gotta change extension and filename
        EXT=""
        FILENAME=$(printf "%s" "$file" | awk -F '/' '{ print $NF}' )
        # set flag for deciding how to rename
        FLAG=1
    else
        FILENAME=$( printf "%s" "$file" | awk -F '/' -v var=$EXT '{gsub("."var,"");print $NF}'   ) # filename, without path, lst in
    fi

    NUMLINES=$(wc -l "$file" | awk '{print $1}') # line count

    if [ $FLAG -eq 0 ];then
         echo "$file" renamed as "$OUTPUTDIR"/"$FILENAME"_"$NUMLINES"."$EXT"
        # cp "$file" "$OUTPUTDIR"/"$FILENAME"_"$NUMLINES"."$EXT" # uncomment when necessary
    else
        echo "$file" renamed as "$OUTPUTDIR"/"$FILENAME"_"$NUMLINES""$EXT"
        # cp "$file" "$OUTPUTDIR"/"$FILENAME"_"$NUMLINES""$EXT" # uncomment when necessary
    fi

    #printf "\n"

done

Guión en acción

$./renamer.sh                                                                                                           
/home/xieerqi/substitutions/file. renamed as /home/xieerqi/substitutions/output/file._0
/home/xieerqi/substitutions/file.. renamed as /home/xieerqi/substitutions/output/file.._0
/home/xieerqi/substitutions/file.1.jpg renamed as /home/xieerqi/substitutions/output/file.1_3.jpg
/home/xieerqi/substitutions/file.1.test.jpg renamed as /home/xieerqi/substitutions/output/file.1.test_3.jpg
/home/xieerqi/substitutions/file.1.test.txt renamed as /home/xieerqi/substitutions/output/file.1.test_2.txt
/home/xieerqi/substitutions/file.1.txt renamed as /home/xieerqi/substitutions/output/file.1_2.txt
/home/xieerqi/substitutions/file.2.jpg renamed as /home/xieerqi/substitutions/output/file.2_3.jpg
/home/xieerqi/substitutions/file.2.test.jpg renamed as /home/xieerqi/substitutions/output/file.2.test_3.jpg
/home/xieerqi/substitutions/file.2.test.txt renamed as /home/xieerqi/substitutions/output/file.2.test_2.txt
/home/xieerqi/substitutions/file.2.txt renamed as /home/xieerqi/substitutions/output/file.2_2.txt
/home/xieerqi/substitutions/foo..bar.txt renamed as /home/xieerqi/substitutions/output/foo..bar_4.txt

Tenga en cuenta que no hay líneas en el archivo. y archivo .., por lo tanto, el recuento de líneas es 0

Un agradecimiento especial a terdon y Helio por revisar el guión y las ediciones sugeridas

Sergiy Kolodyazhnyy
fuente
2

Otra manera bash, desarrollada con @Helio en el chat :

for file in *
do
    echo "$file"
    [[ -f "$file" ]] || continue
    [[ $file =~ (.*)(\.[^.]+)$ ]]
    cp "$file" "output/${BASH_REMATCH[1]:-$file}_$(wc -l < "$file")${BASH_REMATCH[2]}"
done

El tipo monocular de aspecto extraño con una segunda cabeza atrofiada ( (.*)(\.[^.]+)$) debe coincidir solo con las extensiones adecuadas ( .foo, no ..). Si no hay extensión, la BASH_REMATCHmatriz estará vacía. Podemos aprovechar esto usando un valor predeterminado para el nombre del archivo ${BASH_REMATCH[1]:-$file}, y simplemente usando la extensión como está.

Para manejar archivos de puntos, puede usar find, como lo sugieren terdon y Helio .

find -maxdepth 1 -type f -printf '%P\0' | 
while IFS= read -r -d '' file
do
    [[ $file =~ (.*)(\.[^.]+)$ ]]
    cp "$file" "output/${BASH_REMATCH[1]:-$file}_$(wc -l < "$file")${BASH_REMATCH[2]}"
done
muru
fuente
+1: No podría hacer una explicación para el comando. ;-)
Helio