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/'*
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
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
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
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
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' *
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
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