2013-03-02 46 views
27

爲什麼「慶典:壞替代」,在sh文件使用代碼時

for i in *.mp4; do ffmpeg -i "$i" "${i/.mp4/.mp3}"; done 

工作,如果我用它在控制檯,但給我一個「壞替代」的錯誤,如果我使用相同的代碼在.sh文件中?

for i in *.mp4 
do 
    ffmpeg -i "$i" "${i/.mp4/.mp3}" 
done 
+5

您是否使用腳本中的#!/ bin/sh或#!/ bin/bash? – 2013-03-02 21:10:37

+1

在控制檯中,命令由'bash' shell執行。如果你在你的腳本中使用'#!/ bin/sh',那麼'sh' shell試圖執行並因此發生錯誤。 – jitendra 2013-03-02 21:16:59

+0

我在第一行寫了#!/ bin/sh ... – WhatIsName 2013-03-02 21:18:01

回答

51

#!/bin/sh

的意義。這是因爲您使用的腳本#!/bin/sh,你應該將其更改爲#!/bin/bash修復。

#!/bin/bash 
for i in *.mp4 
do 
    ffmpeg -i "$i" "${i/.mp4/.mp3}" 
done 

人們使用#!/bin/sh當只使用最大的可移植性的一組特徵的限制(由POSIX標準定義)。 #!/bin/bash對於用戶腳本來說非常好。 /bin/sh通常符合鏈接到最小的符合POSIX的外殼或標準外殼(例如bash)。在後一種情況的bash是在兼容模式下,這是在manpage解釋運行:

如果bash以名稱sh啓動,它試圖儘可能接近模仿sh歷史版本的啓動行爲成爲可能,同時符合POSIX標準。

建議修改你的腳本:

  • 它被認爲是很好的做法,周圍使用變量引號("$i"而不是$i)。如果存儲的文件名包含空格字符,則引用變量將防止出現問題。
  • 我喜歡你使用高級parameter expansion。我建議使用"${i%.mp4}.mp3"(而不是"${i/.mp4/.mp3}"),因爲${parameter%word}只在最後替代(例如名爲foo.mp4.backup的文件)。
+0

+1 - 這也取決於它的執行方式,I.E.你不能聲明爲'#!/ bin/bash'然後用'sh'調用或者聲明爲'#!/ bin/sh'並且用'bash'調用,至少在Debian 7中你會看到兩個錯誤。該聲明需要匹配調用。 – webLacky3rdClass 2013-12-13 19:03:32

+0

@CharlesDuffy這是一個錯字/混亂,我可能是指引號。 – 2016-01-10 00:06:05

+0

我認爲使用'#!/ usr/bin/env bash'會是更好的方法。 – Hozefa 2016-09-11 00:22:48

9

${var/x/y/}構造不是POSIX。你的情況,你只是在與其他字符串變量和粘性的結尾處,刪除一個字符串,便攜式POSIX解決方案是使用

#!/bin/sh 
for i in *.mp4; do 
    ffmpeg -i "$i" "${i%.mp4}.mp3" 
done 

,甚至更短,ffmpeg -i "$i" "${i%4}3"

這些結構的權威性塗料是關於Parameter Expansion for the POSIX shell的章節。