Renaming files to add a suffix

I need a command to rename all files in the current working directory, in a way that the new filename will be the same as the old, but including a suffix corresponding to the number of lines of the original files (e.g. if the file f has 10 lines then it should be renamed to f_10).

Here's my (non-working) attempt:

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

Solution 1:

How about:

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

For example:

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

If you want to keep extensions (if present), use this instead:

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

Solution 2:

You can try this one liner:

find . -maxdepth 1 -type f -exec bash -c 'mv -i "$1" "$1.$(wc -l <"$1")"' _ {} \;
  • This will find all files in the current working directory (find . -maxdepth 1 -type f)

  • Then we are running a shell instance over the files found to rename the files to append the number of lines.

Example :

$ 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

Solution 3:

Another way which preserves the extension (if present) using rename:

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

If the result is the expected one, remove the -n option:

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

Solution 4:

Using find:

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

Example

% 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

Solution 5:

Just for fun and giggles a solution with rename. Since rename is a Perl tool that accepts an arbitrary string that is eval'd, you can do all sorts of shenanigans. A solution that seems to work is the following:

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