我将这个 shell 脚本保存在一个文件中:它执行一些基本的字符串替换。
#!/bin/sh
html_file=$1
echo "html_file = $html_file"
substr=.pdf
pdf_file="${html_file/.html/.pdf}"
echo "pdf_file = $pdf_file"
如果我将其粘贴到命令行中,它工作正常:
$ html_file="/home/max/for_pauld/test_no_base64.html"
echo "html_file = $html_file"
substr=.pdf
pdf_file="${html_file/.html/.pdf}"
echo "pdf_file = $pdf_file"
给出
html_file = /home/max/for_pauld/test_no_base64.html
pdf_file = /home/max/for_pauld/test_no_base64.pdf
这是上面 echo 的输出 - 它正在按预期工作。
但是,当我调用脚本时,
$ saucer "/home/max/for_pauld/test_no_base64.html"
我得到这个输出:
html_file = /home/max/for_pauld/test_no_base64.html
/home/max/bin/saucer: 5: /home/max/bin/saucer: Bad substitution
我的脚本是否使用了不同版本的 bash 或者其他版本?我需要改变我的 shebang 线吗?
答案1
什么是 sh
sh
(或 Shell 命令语言)是一种编程语言,由POSIX标准。它有许多实现(ksh88
、dash
、 ...)。bash
也可以被认为是一个实现sh
(见下文)。
因为sh
是一个规范,而不是一个实现,/bin/sh
是大多数 POSIX 系统上实际实现的符号链接(或硬链接)。
什么是bash
bash
最初是作为sh
兼容的实现(尽管它早于 POSIX 标准几年),但随着时间的推移,它已经获得了许多扩展。其中许多扩展可能会更改有效 POSIX shell 脚本的行为,因此其本身bash
并不是有效的 POSIX shell。相反,它是 POSIX shell 语言的一种方言。
bash
支持--posix
开关,这使得它更符合 POSIX 标准。如果作为sh
.
sh = bash?
很长一段时间以来,/bin/sh
用于指/bin/bash
大多数 GNU/Linux 系统。结果,几乎可以安全地忽略两者之间的差异。但这种情况最近开始发生变化。
一些流行的系统示例/bin/sh
(/bin/bash
其中一些/bin/bash
甚至可能不存在)是:
- 现代 Debian 和 Ubuntu 系统,默认符号链接
sh
到dash
; - 忙碌盒,它通常作为 Linux 系统启动时间的一部分运行
initramfs
。它使用ash
shell 实现。 - BSD,以及一般的任何非 Linux 系统。 OpenBSD 使用
pdksh
Korn shell 的后代。 FreeBSDsh
是原始 UNIX Bourne shell 的后代。 Solaris 有自己的系统sh
,但在很长一段时间内不符合 POSIX 标准;可以从以下位置免费实施传家宝项目。
如何找出/bin/sh
系统上的指向?
复杂的是,它/bin/sh
可能是符号链接或硬链接。如果它是一个符号链接,便携的解决方法是:
% file -h /bin/sh
/bin/sh: symbolic link to bash
如果是硬链接,请尝试
% find -L /bin -samefile /bin/sh
/bin/sh
/bin/bash
事实上,该-L
标志涵盖了符号链接和硬链接,但这种方法的缺点是不可移植——POSIX不需要 find
支持该-samefile
选项,尽管两者GNU 查找和FreeBSD 查找支持它。
舍邦线
最终,您可以通过编写“shebang”行来决定使用哪一个。
例如
#!/bin/sh
将使用sh
(以及无论它指向什么),
#!/bin/bash
/bin/bash
如果可用则使用(如果不可用则失败并显示错误消息)。当然,你也可以指定其他实现,例如
#!/bin/dash
使用哪一个
对于我自己的脚本,我更喜欢sh
,原因如下:
- 它是标准化的
- 它更简单、更容易学习
- 它可以跨 POSIX 系统移植——即使它们碰巧没有
bash
,它们也需要有sh
bash
使用也有优点。它的特性使编程更加方便并且类似于其他现代编程语言的编程。其中包括作用域局部变量和数组等。 Plainsh
是一种非常简约的编程语言。
答案2
除了 @Hunter.S.Thompson 的出色回答外,我想指出脚本的不可移植部分是
pdf_file="${html_file/.html/.pdf}"
这${variable/search/replace}
是一个 GNU 扩展。但你可以使用纯 POSIX 轻松避免它:
pdf_file="${html_file%.html}".pdf
跟随 Hunter,这是比将 shebang 更改为更好的解决方案#! /bin/bash