2014-06-05 55 views
0

我想通过仅更改文件名的一部分并根据另一个文件的列表中的完全匹配来重命名一堆文件。举例来说,如果我有这些文件的名称:根据另一个文件的内容中的完全匹配重命名文件名的一部分

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

,我想根据这些精确的匹配,这是在所谓的replacements.txt另一个文件中查找和替换:

ACGT name1 
TTTTTC longername12 
ACCCGGG nam7 
ACGTA another4 

使所需的结果文件名将是

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

我不想更改内容。到目前为止,我已经根据我在本网站上的搜索结果尝试过sedmv。随着sed我发现了如何利用我的名单替换该文件的内容:

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

mv我已经找到一种方法来重命名文件,如果有一个简单的替换:

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

但我怎么能把他们放在一起做我想做的事情?

谢谢你的帮助!

回答

0

您可以完美地mbine您forwhile循环只使用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 

sed另一个解决办法在于使用e命令执行的替换(小心使用的结果!首先尝试输入e以打印将执行的命令)。

因此:

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

会分析你的replacements.txt文件,并根据需要重命名你的所有.txt文件。

我们只需要添加一个循环来处理其他的一些推广:

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 

(请注意,你应该得到的错误信息时,它会尝试重命名不存在的文件,例如,当它试图执行mv sample_ACGT.fq sample_name1.fq但文件sample_ACGT.fq不存在)

+0

谢谢,Qeole。我不能让'sed'命令工作...我需要为我的情况编辑一些东西吗?我还尝试过使用'mv'的第一个解决方案,在对我的replacements.txt文件进行排序后应该可以工作,就像Joe上面给出的答案一样。 – user2250055

+0

@ user2250055我写的第一个'sed'行只对'.txt'文件有效。问题是否可以从这个问题来解决你输入了什么命令? – Qeole

+0

我完全复制并粘贴了你的命令,但大多数情况下,我指的是'sed'循环...我得到每个文件的错误,例如:mv:can not stat'sample_ACGTA':没有这样的文件或目录。有什么想法吗?正如你所提到的,'sed'命令行的一个作用不同,只是它不处理非.txt扩展名。再次感谢! – user2250055

0

你可以使用awk生成命令:

% 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 

然后要么复制/粘贴或管道直接输出到你的shell:

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

如果要使用更长的匹配字符串首先,首先对替代品进行排序:

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

谢谢乔。这主要是有效的......唯一的问题是,当它用name1代替ACGT时,它将用name1A替代ACGTA,而不是像replacement.txt中指定的那样替换ACGTA。任何其他建议? – user2250055

+0

'sort -r replacements.txt',所以最长匹配字符串首先被使用。我会将其添加到答案中。 – Joe

+0

我认为'排序'工程,除非没有'-r' ...再次感谢!出于好奇,是否还有任何直接的方法可以像我最初想的那样用'sed'来实现呢? – user2250055

相关问题