2013-03-02 13 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的章节。