Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

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

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 these file names:

sample_ACGTA.txt
sample_ACGTA.fq.abc
sample_ACGT.txt
sample_TTTTTC.tsv
sample_ACCCGGG.fq
sample_ACCCGGG.txt
otherfile.txt

and I want to find and replace based on these exact matches, which are found in another file called replacements.txt:

ACGT    name1
TTTTTC  longername12
ACCCGGG nam7
ACGTA   another4

So that the desired resulting file names would be

sample_another4.txt
sample_another4.fq.abc
sample_name1.txt
sample_longername12.tsv
sample_nam7.fq
sample_nam7.txt
otherfile.txt

I do not want to change the contents. So far I have tried sed and mv based on my search results on this website. With sed I found out how to replace the contents of the file using my list:

while read from to; do
  sed -i "s/$from/$to/" infile ;
done < replacements.txt, 

and with mv I have found a way to rename files if there is one simple replacement:

for files in sample_*; do
  mv "$files" "${files/ACGTA/another4}"
done 

But how can I put them together to do what I would like?

Thank you for your help!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...