'batch rename matching files using 1st field to replace and 2nd as search criteria

I have a very large selection of files eg.

foo_de.vtt, foo_en.vtt, foo_es.vtt, foo_fr.vtt, foo_pt.vtt, baa_de.vtt, baa_en.vtt, baa_es.vtt, baa_fr.vtt, baa_pt.vtt... etc.

I have created a tab separated file, filenames.txt containing the current string and replacement string eg.

foo    1000
baa    1016
...etc

I want to rename all of the files to get the following:

1000_de.vtt, 1000_en.vtt, 1000_es.vtt, 1000_fr.vtt, 1000_pt.vtt, 1016_de.vtt, 1016_en.vtt, 1016_es.vtt, 1016_fr.vtt, 1016_pt.vtt

I know I can use a utility like rename to do it manually term by term eg: rename 's/foo/1000/g' *.vtt

could i chain this into an awk command so that it could run through the filenames.txt? or is there an easier way to do it just in awk? I know I can rename with awk such as:

find . -type f | awk -v mvCmd='mv "%s" "%s"\n' \
    '{ old=$0;
       gsub(/foo/,"1000");
       printf mvCmd,old,$0;
     }' | sh

How can I get awk to process filenames.txt and do all of this in one go? This question is similar but uses sed. I feel that being tab separated this should be quite easy in awk?

First ever post so please be gentle!

Solution

Thanks for all your help. Ultimately I was able to solve by adapting your answers to the following:

while read new old; do
  rename "s/$old/$new/g" *.vtt;
done < filenames.txt


Solution 1:[1]

I'm assuming that the strings in the TSV file are literals (not regexes nor globs) and that the part to be replaced can be located anywhere in the filenames.

With that said, you can use mv with shell globs and bash parameter expansion:

#!/bin/bash

while IFS=$'\t' read -r old new
do
    for f in *"$old"*.vtt
    do
        mv "$f" "${f/"$old"/$new}"
    done
done < file.tsv

Or with GNU rename (more performant):

while IFS=$'\t' read -r old new
do
    rename "$old" "$new" *"$old"*.vtt
done < file.tsv

Solution 2:[2]

Using sed

while read old new; do 
    sed "s/$old\(.*\)/mv & $new\1/e" <(find . -name '*.vtt' -printf '%f\n')  
done < filenames.txt

Solution 3:[3]

This might work for you (GNU sed and rename):

sed -E 's#(.*)\t(.*)#rename -n '\''s/\1/\2/'\'' \1*#e' ../file

This builds a script which renames the files in the current directory using file to match and replace parts of the filenames.

Once you are happy with the results, remove the -n and the renaming will be enacted.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 HatLess
Solution 3 potong