2013-07-06 74 views
0

我想寫一個簡單的bash腳本來允許我重命名一些格式不好的電視節目文件名(並且沒有被xbmc拾取)。我能夠得到awk命令來打印出我想要的輸出結果,但只要我將它放入反引號(或重音字符)中,以便我可以合併mv命令,就會出錯。awk命令運行良好,直到「反引號」被插入

我工作的awk命令如下所示(上面有一個簡單的for循環來遍歷目錄中的所有文件)。

echo $i | awk -F" " '{print $1 "\\ -\\ S0" $3 "E" $5 ".avi"}' 

然而,當我添加mv命令它,

mv $i `echo $i | awk -F" " '{print $1 "\\ -\\ S0" $3 "E" $5 ".avi"}'` 

它的錯誤了下列要求:

awk: warning: escape sequence `\ ' treated as plain ` ' 

據我所知,我需要反斜槓在那裏讓mv命令正常工作。

輸入格式的文件名是

Showname Season 1 Episode 01 - Episode Title.avi 
Show Name Season 1 Episode 01 - Episode Title.avi 

我想這是

Showname - S01E01 - Episode Title.avi 
Show Name - S01E01 - Episode Title.avi 

我不是太擔心被包括情節標題(我無法找到任何簡單包括所有額外字段的方式,並且我還有另一個程序用於移動並命名我的所有文件,以便將標題放在那裏)。有些節目的名字中有兩個單詞(所以它可能是顯示名稱),所以我的計劃是隻手動調整腳本以處理各個字段。

有沒有關於如何讓awk與文件名一起正常工作的建議,以防止在使用「反引號」時出現錯誤?

+0

可能的重複[如何使用與空白的目錄上查找?](http://stackoverflow.com/questions/6052325/how-to-use-find-on-dirs-with-white-spaces) – hek2mgl

+2

請注意,因爲你的文件名包含空格(或者至少有趣的是),所以你應該在''mv'命令'和'echo'的''$ i'''周圍使用雙引號。如果文件名中只有單個空格且沒有製表符或換行符,那麼您可以在'echo'中跳過它,但是如果不將它放在雙引號中並且它包含兩個相鄰的文件名空格或前導空格或尾隨空格,或...通常,使用'$(...)'而不是反引號。 –

+1

通過給出幾個(一個或兩個)樣本輸入文件名稱以及預期的相應輸出文件名稱,可以改進您的問題。我們可以告訴的是,當使用空格進行分割時('-F「」似乎不是必需的),至少有5個部分是文件名,其中只有第一個,第三個和第五個要保留。假設您在輸出中生成反斜槓以保留名稱中的空格,而不是因爲您認爲輸出中的反斜槓是好的。 –

回答

4

請注意,由於您的文件名包含空格(或者至少有趣的文件名),因此您應該在mv命令中使用"$i"左右的雙引號,並在echo中使用雙引號。如果在文件名中只有單個空格且沒有製表符或換行符,則'在回顯中脫離它',但如果不用雙引號括起來並且它包含兩個相鄰空格,則會銷燬文件名,或前導空格或尾隨空格,或...通常,使用$(...)而不是後引號。

通過給出幾個(一個或兩個)樣本輸入文件名以及預期的相應輸出文件名,可以改進您的問題。我們可以告訴的是,當使用空格分隔時(幾乎看起來不需要-F" "),文件名至少有5個部分,其中只有第一個,第三個和第五個要保留。假設您在輸出中生成反斜槓以保留名稱中的空格,而不是因爲您認爲文件名中的反斜槓是個好主意。 (也就是說,反斜槓不會出現在磁盤上的名稱)

既然你周圍有一個循環,我會用awk做到這一點的方法是:

for file in * 
do 
    name=$(echo "$file" | awk '{print $1 " - S0" $3 "E" $5 ".avi"}') 
    mv "$file" "$name" 
done 

有固體這樣做的理由。該作業保留了awk輸出中的空格等(切斷尾隨的換行符,但僅此而已)。然後mv命令行是微不足道的,使用雙引號來防止問題。

嘗試:

for file in * 
do 
    mv "$file" $(echo "$file" | awk '{print $1 " - S0" $3 "E" $5 ".avi"}') 
done 

讓你陷入麻煩的管道輸出由外殼和拆分重新掃描,你必須防止分裂(因此在原代碼中的反斜槓),並擔心其他shell元字符(例如,如果某個節目的名稱中有撇號)。

但是,您可以用雙引號將整個$(...)括起來,然後事情就會奏效 - 我會說'如預期的那樣',但實際上並不如我預期的那樣。但隨着雙方bashksh測試表明,這個工程:

for file in * 
do 
    mv "$file" "$(echo "$file" | awk '{print $1 " - S0" $3 "E" $5 ".avi"}')" 
done 

外雙引號只是防止shell擴展$(...)的輸出,並採用$(...)大大簡化生活。用簡單的引號代替$(...)會產生各種各樣的問題;在反引號裏面,你必須逃避各種各樣的事情。但似乎在$(...)記號暫停當前雙引號字符串搜索,並開始搜索關閉)與'正常'解釋中間的東西,這給出了所需的結果。

我覺得雙線(賦值加使用)比較容易理解,但是這個版本在雙引號內用複雜的命令替換也可以。


下面是一些測試代碼,假設你目前沒有一個在當前目錄中名爲spaced-out目錄(和你有在當前目錄寫權限):

mkdir spaced-out 
(
cd spaced-out 
# Create files with spaces in the names 
for file in "part1 x part2 y part3" "show1 a show2 b show3" \ 
      " leader1 x leader2 y leader3 " 
do 
    echo hello world > "$file" 
done 
ls 
ls -l 
# Rename the files 
for file in * 
do 
    mv "$file" "$(echo "$file" | awk '{print $1 " - S0" $3 "E" $5 ".avi"}')" 
done 
# Show results and clean up 
ls -l 
rm -f * 
) 
rmdir spaced-out 

當運行作爲腳本(bash rename.script),它生成:

leader1 x leader2 y leader3 part1 x part2 y part3   show1 a show2 b show3 
total 24 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 leader1 x leader2 y leader3 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 part1 x part2 y part3 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 show1 a show2 b show3 
total 24 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 leader1 - S0leader2Eleader3.avi 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 part1 - S0part2Epart3.avi 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 show1 - S0show2Eshow3.avi 

當作爲bash -x rename.script運行時,它產生:

+ mkdir spaced-out 
+ cd spaced-out 
+ for file in '"part1 x part2 y part3"' '"show1 a show2 b show3"' '" leader1 x leader2 y leader3 "' 
+ echo hello world 
+ for file in '"part1 x part2 y part3"' '"show1 a show2 b show3"' '" leader1 x leader2 y leader3 "' 
+ echo hello world 
+ for file in '"part1 x part2 y part3"' '"show1 a show2 b show3"' '" leader1 x leader2 y leader3 "' 
+ echo hello world 
+ ls 
    leader1 x leader2 y leader3 part1 x part2 y part3   show1 a show2 b show3 
+ ls -l 
total 24 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 leader1 x leader2 y leader3 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 part1 x part2 y part3 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 show1 a show2 b show3 
+ for file in '*' 
++ echo ' leader1 x leader2 y leader3 ' 
++ awk '{print $1 " - S0" $3 "E" $5 ".avi"}' 
+ mv ' leader1 x leader2 y leader3 ' 'leader1 - S0leader2Eleader3.avi' 
+ for file in '*' 
++ echo 'part1 x part2 y part3' 
++ awk '{print $1 " - S0" $3 "E" $5 ".avi"}' 
+ mv 'part1 x part2 y part3' 'part1 - S0part2Epart3.avi' 
+ for file in '*' 
++ echo 'show1 a show2 b show3' 
++ awk '{print $1 " - S0" $3 "E" $5 ".avi"}' 
+ mv 'show1 a show2 b show3' 'show1 - S0show2Eshow3.avi' 
+ ls -l 
total 24 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 leader1 - S0leader2Eleader3.avi 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 part1 - S0part2Epart3.avi 
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 show1 - S0show2Eshow3.avi 
+ rm -f 'leader1 - S0leader2Eleader3.avi' 'part1 - S0part2Epart3.avi' 'show1 - S0show2Eshow3.avi' 
+ rmdir spaced-out 

對於聲稱使用包含空格的文件名稱的腳本,雙倍空間文件名(可選地帶有前導空格和/或尾隨空格)通常是非常好的測試。此代碼不管理包含換行符的文件名; awk腳本將這個名稱視爲兩行輸入,這不是我們想要的。它可以是固定的;它通常不值得麻煩,除非你需要你的腳本絕對是防彈的(例如,因爲它將發送給客戶 - 客戶做了最不可思議的事情,並且文件中帶有換行符的名稱完全在他們的能力範圍內,儘管你永遠不會自己做)。

+0

現在我看到*巨大的勝利*。但爲什麼你沒有提到'find -print0'?是什麼東西與此? – hek2mgl

+0

@ hek2mgl:'find -print0'的問題是'awk'不一定能識別以空字節結尾的'行'。 glob表示法對任何有效的名稱都非常滿意;但操作代碼需要識別空終止(而不是換行符終止)輸入。如果你有客戶,你可能需要解決這個問題。我可能會在那時使用Perl; Python也可以。我最後提到了(它可能是固定的)。這是我想到的那種事情。但對於這個問題,這幾乎肯定是過度的。 –

+0

我剛剛意識到,在我工作之後,我從來沒有回到這裏,但在查看您的回覆時,它確實看起來是最好的方式。當我不在手機上試圖讓所有東西都沉入水中時,我將不得不再次探究這一點。再次感謝! (對於一年的延遲抱歉) – bassmadrigal

0

那麼,經過更多的挖掘和挑釁之後,我發現我可以在引號中包含mv命令的全部目標,然後刪除反斜槓。

但後來我想出了一個不同的問題。這是說,mv命令的目標不是目錄。我知道這是不是一個目錄...我想在這裏重新命名一些文件...(嘰,嘰)

mv: target 'Showname - S01E01.avi' is not a directory 

無論如何,經過谷歌搜索,我發現了一個LinuxQuestions post,這顯然是由於文件名中的空格。我可以通過將以下內容添加到腳本的開頭來解決這個問題。

IFS=' 
' 

現在它重命名我的文件,以一個體面的命名方案,以便其他程序/服務可以對它們撿起並妥善

1

增加他們試試這個:

for file in * 
do 
    set -- $file 
    mv -- "$i" "$(printf "%s - %s %sE%s.avi" "$1" "$file" "$3" "$5")" 
done 

這是一種猜測,但 - 您需要顯示您的輸入和輸出文件名稱的實際外觀,而不僅僅是一個無法將其轉換的命令!

+1

''我$「」不需要是「」$ file「'?我不清楚爲什麼要在輸出中插入''file'';原始名稱中包含'S0'而不是'$ 0'。 –

相關問題