我想通过仅更改文件名的一部分来重命名一堆文件,并根据另一个文件中列表中的完全匹配来执行此操作。例如,如果我有这些文件名:
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
我不想改变内容。到目前为止,我已根据此网站上的搜索结果尝试了sed
和mv
。使用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 :(得分: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
答案 1 :(得分:0)
您可以完美地将for
和while
循环合并为仅使用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
不存在时)