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
请参阅sh 和 Bash 之间的区别。要找出您正在使用的 sh readlink -f $(which sh)
:.
确保 bash 特定脚本始终正确运行的最佳方法
最佳做法是:
- 替换
#!/bin/sh
为#!/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
或#!/bin/bash
不必记住哪个脚本是用什么语言编写的。
人们#!/bin/sh
只使用一组有限的功能(由 POSIX 标准定义)以实现最大的可移植性。#!/bin/bash
非常适合利用有用 bash 扩展的用户脚本。
/bin/sh
通常符号链接到最小的 POSIX 兼容 shell 或标准 shell(例如 bash)。即使在后一种情况下,#!/bin/sh
也可能会失败,因为bash
它将在手册页中解释的兼容模式下运行:
如果使用名称 sh 调用 bash,它会尝试尽可能地模仿 sh 的历史版本的启动行为,同时也符合 POSIX 标准。
的意思sh myscript.sh
shebang 仅在您运行./myscript.sh
,/path/to/myscript.sh
或删除扩展名时使用,将脚本放在您的目录中$PATH
,然后运行myscript
.
如果您明确指定解释器,则将使用该解释器。无论shebang说什么,sh myscript.sh
都会强制它运行。sh
这就是为什么仅仅改变 shebang 是不够的。
您应该始终使用其首选解释器运行脚本,因此./myscript.sh
无论何时执行任何脚本时都应首选或类似。
对脚本的其他建议更改:
- 引用变量(
"$i"
而不是$i
)被认为是一种很好的做法。如果存储的文件名包含空格字符,带引号的变量将防止出现问题。
- 我喜欢你使用高级参数扩展。我建议使用
"${i%.mp4}.mp3"
(而不是"${i/.mp4/.mp3}"
),因为${parameter%word}
仅在末尾替换(例如名为 的文件foo.mp4.backup
)。