Ok, I have many files in a folder that have the string "$varname.txt"` in their name:

for file in find output/ -name "*$varname*.txt" -type f; do echo $file; done


now these files all have two lines and 9 columns to them. I want to add the content of line 2, col 9 to the end of their filname (right before the .txt).

So I know how to print the value of in cell(2, 9) of all these files:

find output/ -name "*$varname*.txt" -type f -exec awk -F' ' 'NR==2{print $9}' {} \;

What I struggle with is how to put that string as the last thing before the extension in those filenames


You need to capture the value and construct the new filename with it.

find output/ -name "*$varname*.txt" -type f -exec sh -c '
    for file; do
        value=$(awk "NR==2 {print \$9; exit}" "$file")
        echo mv "$file" "${file%.*}$value.${file##*.}"
' sh {} +

I'm calling a shell script in the -exec directive, passing several filenames to it (with -exec ... + instead of -exec ... \;)

The trailing "sh" becomes $0, and the filenames go into $1, $2, etc

  • I came to the exact same solution, but I’d replace txt with ${file##*.}. – dessert Jun 24 '18 at 10:56
  • 1
    Why? We are explicitly looking for txt files based on the find command. We already know exactly what the filename extension is. – glenn jackman Jun 24 '18 at 10:58
  • 1
    Then again, if we change the -name pattern, we wouldn't have to also change the sh code. Or if the name pattern is dynamic. I see your point – glenn jackman Jun 24 '18 at 11:07
  • Exactly – it’s a good thing to make code as universally applicable as possible. Someone searching for “add value to file name” might stumble across this and wonder. – dessert Jun 24 '18 at 11:09
  • 1
    @user2413 glenn forgot to mention that this only prints what will be done, you need to remove echo to perform the renaming, see my answer below where I do the same. – dessert Jun 24 '18 at 11:28

Here’s a GNU parallel Install parallel approach:

find output/ -name "*$varname*.txt" -type f -print0 |
parallel -0 'echo mv {} {.}$(awk -F" " "NR==2{print\$9}" {}).{=s/.*\.//=}'

This pipes the zero-delimited file list to parallel which lists the renaming commands – remove echo if it does the right thing. parallel comes with handy replacement strings, {} is replaced by the (currently processed) input file name, {.} by the input filename without extension and with {=perl expression=} you can run anything perl can do, like a substitution here. The output of your awk command is simply added using Command Substitution.

  • 1
    Thanks for the idea. In this case, this is part of a bash function that will itself be called by parallel (so in my individual use case it is a bit moot hence my awarding the points to @glenn jackman's answer) but I'm sure other reader will appreciate doing these sort of tasks 8 times faster! – user2413 Jun 24 '18 at 11:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.