为什么我的 Bash 代码在使用 'sh' 运行时会失败? [英] Why does my Bash code fail when I run it with 'sh'?

查看:44
本文介绍了为什么我的 Bash 代码在使用 'sh' 运行时会失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一行代码在我的终端中运行良好:

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).

最佳做法是两者:

  1. #!/bin/sh 替换为 #!/bin/bash(或脚本所依赖的任何其他 shell).
  2. 使用 ./myscript.sh/path/to/myscript.sh 运行此脚本(以及所有其他脚本!),不带前导 shbash.
  1. Replace #!/bin/sh with #!/bin/bash (or whichever other shell your script depends on).
  2. Run this script (and all others!) with ./myscript.sh or /path/to/myscript.sh, without a leading 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

(相关:为什么 ./在脚本前面?)

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 兼容 shell 或标准 shell(例如 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 will run in compatibility mode as explained in the man page:

如果使用名称 sh 调用 bash,它会尝试尽可能模仿 sh 历史版本的启动行为,同时也符合 POSIX 标准.

If bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of sh as closely as possible, while conforming to the POSIX standard as well.

sh myscript.sh

的含义

shebang 只在你运行 ./myscript.sh/path/to/myscript.sh 时使用,或者当你删除扩展名时,把脚本放在在 $PATH 的目录中,然后运行 ​​myscript.

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.

如果您明确指定一个解释器,则将使用该解释器.sh myscript.sh 将强制它与 sh 一起运行,无论 shebang 说什么.这就是为什么仅仅改变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 named foo.mp4.backup).

这篇关于为什么我的 Bash 代码在使用 'sh' 运行时会失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆