问题描述
我有一行代码在我的终端上可以正常工作:
I have a line of code that works fine in my terminal:
for i in *.mp4; do echo ffmpeg -i "$i" "${i/.mp4/.mp3}"; done
然后我将完全相同的代码行放在脚本myscript.sh
中:
Then I put the exact same line of code in a script myscript.sh
:
#!/bin/sh
for i in *.mp4; do echo ffmpeg -i "$i" "${i/.mp4/.mp3}"; done
但是,现在运行它时出现错误:
However, now I get an error when running it:
$ sh myscript.sh
myscript.sh: 2: myscript.sh: Bad substitution
基于其他问题,我尝试将shebang更改为#!/bin/bash
,但得到了完全相同的错误.为什么我不能运行此脚本?
Based on other questions I tried changing the shebang to #!/bin/bash
, but I get the exact same error. Why can't I run this script?
推荐答案
TL; DR:由于您使用的是bash
特定功能,因此脚本必须使用bash
而不是sh
运行:
TL;DR: Since you are using bash
specific features, your script has to run with bash
and not with 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)
.
See Difference between sh and bash. To find out which sh you are using: readlink -f $(which sh)
.
最佳实践是两者:
- 将
#!/bin/sh
替换为#!/bin/bash
(或脚本所依赖的其他Shell). - 使用
./myscript.sh
或/path/to/myscript.sh
运行此脚本(以及其他所有脚本!),而无需前导sh
或bash
.
- Replace
#!/bin/sh
with#!/bin/bash
(or whichever other shell your script depends on). - Run this script (and all others!) with
./myscript.sh
or/path/to/myscript.sh
, without a leadingsh
orbash
.
这是一个例子:
$ 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
(相关:)
shebang建议系统应使用哪个shell运行脚本.这样,您就可以指定#!/usr/bin/python
或#!/bin/bash
,这样您就不必记住哪个脚本是用哪种语言编写的.
The shebang suggests which shell the system should use to run a script. This allows you to specify #!/usr/bin/python
or #!/bin/bash
so that you don't have to remember which script is written in what language.
当人们仅使用一组有限的功能(由POSIX标准定义)以实现最大的可移植性时,他们会使用#!/bin/sh
. #!/bin/bash
非常适合利用有用的bash扩展的用户脚本.
People use #!/bin/sh
when they only use a limited set of features (defined by the POSIX standard) for maximum portability. #!/bin/bash
is perfectly fine for user scripts that take advantage of useful bash extensions.
/bin/sh
通常与最小POSIX兼容外壳或标准外壳(例如bash)建立符号链接.即使在后一种情况下,#!/bin/sh
也可能会失败,因为bash
将以兼容模式运行,如联机帮助页:
/bin/sh
is usually symlinked to either a minimal POSIX compliant shell or to a standard shell (e.g. bash). Even in the latter case, #!/bin/sh
may fail because bash
wil run in compatibility mode as explained in the manpage:
sh myscript.sh
的含义仅当您运行./myscript.sh
,/path/to/myscript.sh
或放置扩展名,将脚本放在$PATH
中的目录中并运行myscript
时,才使用shebang.
The meaning of sh myscript.sh
The shebang is only used when you run ./myscript.sh
, /path/to/myscript.sh
, or when you drop the extension, put the script in a directory in your $PATH
, and just run myscript
.
如果您明确指定解释器,则将使用该解释器.不管shebang说什么,sh myscript.sh
都会强制它与sh
一起运行.这就是为什么仅仅改变shebang还是不够的.
If you explicitly specify an interpreter, that interpreter will be used. sh myscript.sh
will force it to run with sh
, no matter what the shebang says. This is why changing the shebang is not enough by itself.
您应该始终使用脚本的首选解释器运行脚本,因此无论何时执行任何脚本,都首选./myscript.sh
或类似脚本.
You should always run the script with its preferred interpreter, so prefer ./myscript.sh
or similar whenever you execute any script.
- 引用变量(
"$i"
而不是$i
)被认为是一种好习惯.如果存储的文件名包含空格字符,带引号的变量将防止出现问题. - 我喜欢您使用高级的参数扩展.我建议使用
"${i%.mp4}.mp3"
(而不是"${i/.mp4/.mp3}"
),因为${parameter%word}
仅在末尾替换(例如,名为foo.mp4.backup
的文件).
- It is considered good practice to quote variables (
"$i"
instead of$i
). Quoted variables will prevent problems if the stored file name contains white space characters. - I like that you use advanced parameter expansion. I suggest to use
"${i%.mp4}.mp3"
(instead of"${i/.mp4/.mp3}"
), since${parameter%word}
only substitutes at the end (for example a file namedfoo.mp4.backup
).
这篇关于为什么在使用sh运行bash代码时失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!