Append wc lines to filename

一世执手 提交于 2019-12-10 16:16:00

问题


Title says it all. I've managed to get just the lines with this:

lines=$(wc file.txt | awk {'print $1'});

But I could use an assist appending this to the filename. Bonus points for showing me how to loop this over all the .txt files in the current directory.


回答1:


find -name '*.txt' -execdir bash -c \
  'mv -v "$0" "${0%.txt}_$(wc -l < "$0").txt"' {} \;

where

  • the bash command is executed for each (\;) matched file;
  • {} is replaced by the currently processed filename and passed as the first argument ($0) to the script;
  • ${0%.txt} deletes shortest match of .txt from back of the string (see the official Bash-scripting guide);
  • wc -l < "$0" prints only the number of lines in the file (see answers to this question, for example)

Sample output:

'./file-a.txt' -> 'file-a_5.txt'
'./file with spaces.txt' -> 'file with spaces_8.txt'



回答2:


You could use the rename command, which is actually a Perl script, as follows:

rename --dry-run 'my $fn=$_; open my $fh,"<$_"; while(<$fh>){}; $_=$fn; s/.txt$/-$..txt/' *txt

Sample Output

'tight_layout1.txt' would be renamed to 'tight_layout1-519.txt'
'tight_layout2.txt' would be renamed to 'tight_layout2-1122.txt'
'tight_layout3.txt' would be renamed to 'tight_layout3-921.txt'
'tight_layout4.txt' would be renamed to 'tight_layout4-1122.txt'

If you like what it says, remove the --dry-run and run again.

The script counts the lines in the file without using any external processes and then renames them as you ask, also without using any external processes, so it quite efficient.

Or, if you are happy to invoke an external process to count the lines, and avoid the Perl method above:

rename --dry-run 's/\.txt$/-`grep -ch "^" "$_"` . ".txt"/e' *txt



回答3:


Use rename command

for file in *.txt; do 
 lines=$(wc ${file} | awk {'print $1'});
 rename s/$/${lines}/ ${file}
done



回答4:


#/bin/bash

files=$(find . -maxdepth 1 -type f -name '*.txt' -printf '%f\n')
for file in $files; do
    lines=$(wc $file | awk {'print $1'});
    extension="${file##*.}"
    filename="${file%.*}"
    mv "$file" "${filename}${lines}.${extension}"
done

You can adjust maxdepth accordingly.




回答5:


you can do like this as well:

for file in "path_to_file"/'your_filename_pattern'
    do
      lines=$(wc $file | awk {'print $1'})
      mv $file $file'_'$lines
    done

example:

    for file in /oradata/SCRIPTS_EL/text*
    do
        lines=$(wc $file | awk {'print $1'})
        mv $file $file'_'$lines
    done



回答6:


This would work, but there are definitely more elegant ways.

for i in *.txt; do
  mv "$i" ${i/.txt/}_$(wc $i | awk {'print $1'})_.txt; 
done

Result would put the line numbers nicely before the .txt. Like:

file1_1_.txt 
file2_25_.txt



回答7:


You could use grep -c '^' to get the number of lines, instead of wc and awk:

for file in *.txt; do
  [[ ! -f $file ]] && continue # skip over entries that are not regular files
  #
  # move file.txt to file.txt.N where N is the number of lines in file
  #
  # this naming convention has the advantage that if we run the loop again,
  # we will not reprocess the files which were processed earlier
  mv "$file" "$file".$(grep -c '^' "$file")
done



回答8:


{ linecount[FILENAME] = FNR }
END {
    linecount[FILENAME] = FNR
    for (file in linecount) {
        newname = gensub(/\.[^\.]*$/, "-"linecount[file]"&", 1, file)
        q = "'"; qq = "'\"'\"'"; gsub(q, qq, newname)
        print "mv -i -v '" gensub(q, qq, "g", file) "' '" newname "'"
    }
    close(c)
}

Save the above awk script in a file, say wcmv.awk, the run it like:

awk -f wcmv.awk *.txt

It will list the commands that need to be run to rename the files in the required way (except that it will ignore empty files). To actually execute them you can pipe the output to a shell for execution as follows.

awk -f wcmv.awk *.txt | sh

Like it goes with all irreversible batch operations, be careful and execute commands only if they look okay.




回答9:


 awk '
  BEGIN{ for ( i=1;i<ARGC;i++ ) Files[ARGV[i]]=0 }

  {Files[FILENAME]++}

  END{for (file in Files) {
        # if( file !~ "_" Files[file] ".txt$") {

           fileF=file;gsub( /\047/, "\047\"\047\"\047", fileF)
           fileT=fileF;sub( /.txt$/, "_" Files[file] ".txt", fileT)

           system( sprintf( "mv \047%s\047 \047%s\047", fileF, fileT))

        #   }
        }
     }' *.txt

Another way with awk to manage easier a second loop by allowing more control on name (like avoiding one having already the count inside from previous cycle)

Due to good remark of @gniourf_gniourf:

  • file name with space inside are possible
  • tiny code is now heavy for such a small task


来源:https://stackoverflow.com/questions/41843165/append-wc-lines-to-filename

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!