TL;DR:由于您使用的是 Bash 特定功能,因此您的脚本必须与 Bash 一起运行,而不是与sh
:
$ sh myscript.sh
myscript.sh: 2: myscript.sh: Bad substitution
$ bash myscript.sh
ffmpeg -i bar.mp4 bar.mp3
ffmpeg -i foo.mp4 foo.mp3
See sh 和 Bash 之间的区别。要了解您正在使用哪个 sh:readlink -f $(which sh)
.
确保 bash 特定脚本始终正确运行的最佳方法
最佳做法是both:
- Replace
#!/bin/sh
with #!/bin/bash
(或者您的脚本所依赖的任何其他 shell)。
- 运行此脚本(以及所有其他脚本!)
./myscript.sh
or /path/to/myscript.sh
,没有前导sh
or bash
.
这是一个例子:
$ cat myscript.sh
#!/bin/bash
for i in *.mp4
do
echo ffmpeg -i "$i" "${i/.mp4/.mp3}"
done
$ chmod +x myscript.sh # Ensure script is executable
$ ./myscript.sh
ffmpeg -i bar.mp4 bar.mp3
ffmpeg -i foo.mp4 foo.mp3
(有关的:为什么脚本前面要加./?)
的含义#!/bin/sh
shebang 建议系统应使用哪个 shell 来运行脚本。这允许您指定#!/usr/bin/python
or #!/bin/bash
这样您就不必记住哪个脚本是用哪种语言编写的。
人们使用#!/bin/sh
当他们只使用一组有限的功能(由 POSIX 标准定义)来实现最大的可移植性时。#!/bin/bash
对于利用有用的 bash 扩展的用户脚本来说非常合适。
/bin/sh
通常符号链接到最小的 POSIX 兼容 shell 或标准 shell(例如 bash)。即使在后一种情况下,#!/bin/sh
可能会失败,因为bash
将以兼容模式运行,如中所述man page:
如果使用 sh 名称调用 bash,它会尝试尽可能模仿 sh 历史版本的启动行为,同时也符合 POSIX 标准。
的含义sh myscript.sh
shebang 仅在您跑步时使用./myscript.sh
, /path/to/myscript.sh
,或者当您删除扩展程序时,将脚本放入您的目录中$PATH
,然后运行myscript
.
如果您显式指定解释器,则将使用该解释器。sh myscript.sh
将强制它运行sh
,不管shebang说什么。这就是为什么改变 shebang 本身是不够的。
您应该始终使用首选解释器运行脚本,因此更喜欢./myscript.sh
或每当您执行任何脚本时类似的内容。
对脚本的其他建议更改:
- 引用变量被认为是很好的做法(
"$i"
代替$i
)。如果存储的文件名包含空格字符,则引用的变量将防止出现问题。
- 我喜欢你使用先进的参数扩展。我建议使用
"${i%.mp4}.mp3"
(代替"${i/.mp4/.mp3}"
), 自从${parameter%word}
仅在末尾替换(例如名为foo.mp4.backup
).