web-dev-qa-db-fra.com

Renommer des fichiers pour ajouter un suffixe

J'ai besoin d'une commande pour renommer tous les fichiers du répertoire de travail actuel, de manière à ce que le nouveau nom de fichier soit identique à l'ancien, mais avec un suffixe correspondant au nombre de lignes des fichiers d'origine (par exemple, si le fichier f a 10 lignes, il devrait alors être renommé en f_10).

Voici ma tentative (qui ne fonctionne pas):

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

Que diriez-vous:

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

Par exemple:

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

Si vous souhaitez conserver les extensions (si présentes), utilisez plutôt ceci:

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

Vous pouvez essayer cette doublure:

find . -maxdepth 1 -type f -exec bash -c 'mv -i "$1" "$1.$(wc -l <"$1")"' _ {} \;
  • Ceci trouvera tous les fichiers dans le répertoire de travail actuel (find . -maxdepth 1 -type f)

  • Ensuite, nous exécutons une instance de shell sur les fichiers trouvés pour renommer les fichiers afin d’ajouter le nombre de lignes.

Exemple:

$ 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
10
heemayl

Une autre façon de conserver l’extension (si présente) en utilisant rename:

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

Si le résultat est celui attendu, supprimez l'option -n:

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

Utilisation de find:

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

Exemple

% 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
5
A.B.

Juste pour le plaisir et rigole une solution avec rename. rename étant un outil Perl acceptant une chaîne arbitraire évaluée, vous pouvez effectuer toutes sortes de manigances. Une solution qui semble fonctionner est la suivante:

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

Le script ci-dessous couvre plusieurs cas: le point unique et l'extension (fichier.txt), les points multiples et les extensions (fichier.1.txt), les points consécutifs (fichier..foobar.txt) et les points du nom de fichier (fichier. Ou fichier..).

Le script

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

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

Notez qu'il n'y a pas de lignes dans le fichier. et le fichier .., le nombre de lignes est donc 0

Un merci spécial à Terdon et Helio pour avoir révisé le script et les modifications suggérées

2

Un autre moyen, développé avec @ Helio dans le 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

Le gars à l'allure étrange avec une deuxième tête rabougrie ((.*)(\.[^.]+)$) doit correspondre uniquement aux extensions appropriées (.foo, pas ..). S'il n'y a pas d'extension, le tableau BASH_REMATCH sera vide. Nous pouvons en tirer parti en utilisant une valeur par défaut pour le nom de fichier ${BASH_REMATCH[1]:-$file} et en utilisant simplement l'extension telle quelle.

Pour gérer les fichiers de points, vous pouvez utiliser find, comme suggéré par terdon et 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
2
muru