Rename part of file name based on exact match in contents of another file

前端 未结 2 772
盖世英雄少女心
盖世英雄少女心 2021-01-15 17:39

I would like to rename a bunch of files by changing only one part of the file name and doing that based on an exact match in a list in another file. For example, if I have

相关标签:
2条回答
  • 2021-01-15 18:10

    You can perfectly combine your for and while loops to only use mv:

    while read from to ; do
      for i in test* ; do
        if [ "$i" != "${i/$from/$to}" ] ; then
          mv $i ${i/$from/$to}
        fi
      done
    done < replacements.txt
    

    An alternative solution with sed could consist in using the e command that executes the result of a substitution (Use with caution! Try without the ending e first to print what commands would be executed).

    Hence:

    sed 's/\(\w\+\)\s\+\(\w\+\)/mv sample_\1\.txt sample_\2\.txt/e' replacements.txt
    

    would parse your replacements.txt file and rename all your .txt files as desired.

    We just have to add a loop to deal with the other extentions:

    for j in .txt .bak .tsv .fq .fq.abc ; do
      sed "s/\(\w\+\)\s\+\(\w\+\)/mv 'sample_\1$j' 'sample_\2$j'/e" replacements.txt
    done
    

    (Note that you should get error messages when it tries to rename non-existing files, for example when it tries to execute mv sample_ACGT.fq sample_name1.fq but file sample_ACGT.fq does not exist)

    0 讨论(0)
  • 2021-01-15 18:22

    You could use awk to generate commands:

    % awk '{print "for files in sample_*; do mv $files ${files/" $1 "/" $2 "}; done" }' replacements.txt 
    for files in sample_*; do mv $files ${files/ACGT/name1}; done
    for files in sample_*; do mv $files ${files/TTTTTC/longername12}; done
    for files in sample_*; do mv $files ${files/ACCCGGG/nam7}; done
    for files in sample_*; do mv $files ${files/ACGTA/another4}; done
    

    Then either copy/paste or pipe the output directly to your shell:

    % awk '{print "for files in sample_*; do mv $files ${files/" $1 "/" $2 "}; done" }' replacements.txt | bash
    

    If you want the longer match string to be used first, sort the replacements first:

    % sort -r replacements.txt | awk '{print "for files in sample_*; do mv $files ${files/" $1 "/" $2 "}; done" }' | bash
    
    0 讨论(0)
提交回复
热议问题