Rinominare i file per aggiungere un suffisso


13

Ho bisogno di un comando per rinominare tutti i file nella directory di lavoro corrente, in modo che il nuovo nome file sia lo stesso del vecchio, ma includa un suffisso corrispondente al numero di righe dei file originali (ad esempio se il file fha 10 righe quindi dovrebbe essere rinominato f_10).

Ecco il mio tentativo (non funzionante):

 linenum=$(wc -l); find * -type f | grep -v sh | rename 's/^/ec/'*

Potresti dare una risposta! (Se aggiunge qualcosa di nuovo alle risposte esistenti - ma sembra che lo faccia)
Volker Siegel,

Risposte:


13

Che ne dite di:

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

Per esempio:

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

Se vuoi mantenere le estensioni (se presenti), usa invece:

for f in *; do 
    ext=""; 
    [[ $f =~ \. ]] && ext="."${f#*.}; 
    mv "$f" "${f%%.*}"_$(wc -l < "$f")$ext; 
done

Grazie mille! questa riga di comando sembra portare a termine il lavoro, ma come posso cambiare il punto (.) in (_)? Inoltre, poiché il mio script si trova all'interno della cartella, viene anche rinominato e quindi consente di eseguire il mio script una volta (perché il nome dello script cambia ...)
Martin Yeboah,

@MartinYeboah vedere la risposta aggiornata per il _. Per quanto riguarda la sceneggiatura, quale sceneggiatura? Dovrebbe essere eseguito dalla riga di comando, non è necessario uno script. Se si desidera che corrisponda solo ad alcuni file, modificare in *, ad esempio, in *txto qualcosa del genere.
terdon,

grazie mille;) Ho completamente dimenticato che dovrebbe essere eseguito dalla riga di comando :)
Martin Yeboah,

Penso che al wc -l < $fposto del grep sarebbe più facile da capire (e forse migliore da eseguire ma non l'ho verificato).
musiKk,

@musiKk sì, ma poiché le altre risposte stanno usando wc, volevo mostrare un approccio diverso. Ma OK, abbastanza giusto.
terdon,

10

Puoi provare questa fodera:

find . -maxdepth 1 -type f -exec bash -c 'mv -i "$1" "$1.$(wc -l <"$1")"' _ {} \;
  • Questo troverà tutti i file nella directory di lavoro corrente ( find . -maxdepth 1 -type f)

  • Quindi eseguiamo un'istanza della shell sui file trovati per rinominare i file per aggiungere il numero di righe.

Esempio :

$ 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

6

Un altro modo che preserva l'estensione (se presente) utilizzando rename:

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

Se il risultato è quello previsto, rimuovere l' -nopzione:

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

renamegreat =) +1
AB

1
Non fallirebbe su abcd? Cambia il secondo gruppo di acquisizione in (\.?[^\.]+).
ps95,

@ prakharsingh95 Questo è vero, tuttavia (\.?[^\.]+)non va bene perché corrisponderà solo al secondo punto e non corrisponderà a un nome file con punti consecutivi o terminerà con un punto a prescindere. Non è una soluzione facile difficile, l'unico modo sembra fare due sostituzioni.
kos,

@kos hai ragione. Che ne dici di ([^ \.] +). *? ([^ \.] + $) Non sono sicuro dell'ottimalità. Violino di
ps95

1
@ prakharsingh95 non vuoi fuggire .all'interno delle classi di personaggi.
terdon

5

Utilizzando find:

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

Esempio

% 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

Perché il -name "*"? Rimanente dai test? ;)
kos,

1
@kos Vecchia abitudine: \
AB

3

Solo per divertimento e risatine con una soluzione rename. Poiché renameè uno strumento Perl che accetta una stringa arbitraria che viene valutata, puoi eseguire tutti i tipi di shenanigans. Una soluzione che sembra funzionare è la seguente:

rename 's/.*/open(my $f, "<", $_);my $c=()=<$f>;$_."_".$c/e' *

Idea interessante +1
AB

2

Il seguente script copre più casi: il singolo punto e l'estensione (file.txt), più punti ed estensioni (file.1.txt), punti consecutivi (file..foobar.txt) e punti nel nome del file (file. O file..).

Il copione

#!/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

Script in azione

$./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

Si noti che non ci sono righe nel file. e file .., quindi il conteggio delle righe è 0

Un ringraziamento speciale a terdon ed Helio per la revisione della sceneggiatura e le modifiche suggerite


2

Un altro modo bash, sviluppato con @Helio in 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

Lo strano ragazzo monocromatico con una seconda testa stentata ( (.*)(\.[^.]+)$) dovrebbe corrispondere solo alle estensioni appropriate ( .foo, non ..). Se non è presente alcuna estensione, l' BASH_REMATCHarray sarà vuoto. Possiamo trarne vantaggio usando un valore predefinito per il nome file ${BASH_REMATCH[1]:-$file}e usando l'estensione così com'è.

Per gestire i file punto, è possibile utilizzare find, come suggerito da Terdon ed 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

+1: Non sarei in grado di fare una spiegazione per il comando. ;-)
Helio,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.