2014-06-05 94 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

相關問題