我编写的大多数代码都是用 PHP 编写的。我最近开始学习 shell 脚本。我遇到的大多数资源和教程都是针对 Bash 的。有些人对 bashisms 提出警告,有些人则没有。我在这里和 Stack Overflow 上读了很多。
每当答案使用bashisms 时,总会有人评论说:
你不应该使用 <insert bashism here>。它不便携。
即使问题被标记为 ,也会发生这种情况bash。对我来说,这就像告诉 PHP 程序员他们不应该使用 PHP 5 中的新代码,因为它不能与 PHP 4 一起使用。或者告诉某人他们不应该为 Mac 编写一些东西,因为它不能使用在 Windows 上。
当我用 PHP 编写时,我会选择一个最低要求并编写向前兼容的代码。我不担心让它向后兼容。
如果我#!/bin/bash
用作shebang,为什么不应该使用bashisms?我开始觉得有些人只是为了它而喜欢抨击bashisms(双关语)。
人们经常使用bash
和shell
互换——可能是因为 bash 是许多系统上的默认 shell。所以我可以理解添加注释来警告代码使用 bashisms,但我不明白使用它们是错误的含义。
显然,如果我编写的脚本严格供个人使用,我可以用我想要的任何语言编写它。但我想我写的一些代码可能对其他人有用。
在发布之前,我尝试搜索我的问题的答案。我找到了很多关于如何测试可移植性的信息,但找不到任何关于何时这样做很重要的信息。
那么,何时编写可移植脚本很重要?
例如,
我正在尝试查找文件名中有换行符的文件。但我不知道使用什么模式。
以下有效,但如果我想在缩进代码中使用它,则不是很有用。
find . -name '*
*'
Run Code Online (Sandbox Code Playgroud)
我尝试了这两个,他们只成功找到了包含字母n 的文件名:
find . -name '*\n*'
find . -name "*\n*"
Run Code Online (Sandbox Code Playgroud)
然后我找到了如何编写反斜杠转义序列并尝试了这个:
find . -name "*$'\n'*"
Run Code Online (Sandbox Code Playgroud)
但这并没有找到任何东西。我应该如何写模式?
我想 grep 当前脚本,以便我可以从顶部的评论部分打印帮助和版本信息。
我在想这样的事情:
grep '^#h ' -- "$0" | sed -e 's/#h //'
Run Code Online (Sandbox Code Playgroud)
但是后来我想知道如果脚本位于 PATH 中的目录中并且在没有明确指定目录的情况下调用会发生什么。
我搜索了特殊变量的解释,并找到了以下描述$0
:
当前 shell 或程序的名称
当前脚本的文件名
脚本本身的名称
运行时的命令
$0
如果在没有目录的情况下调用脚本,这些都没有说明 的值是否包含目录。最后一个实际上向我暗示它不会。
在我的系统上测试(Bash 4.1)
我在 /usr/local/bin中用一行创建了一个名为scriptname的可执行文件,echo $0
并从不同的位置调用它。
这些是我的结果:
> cd /usr/local/bin/test
> ../scriptname
../scriptname
> cd /usr/local/bin
> ./scriptname
./scriptname
> cd /usr/local
> bin/scriptname
bin/scriptname
> cd /tmp
> /usr/local/bin/scriptname
/usr/local/bin/scriptname
> scriptname
/usr/local/bin/scriptname
Run Code Online (Sandbox Code Playgroud)
在这些测试中, 的值$0
始终与脚本的调用方式完全相同,除非它是在没有任何路径组件的情况下调用的。在这种情况下, 的值$0
是绝对路径。所以看起来传递给另一个命令是安全的。
但是后来我在Stack …
我想知道我是否可以依赖使用find
with-depth
选项时看到的行为,并且用户没有子目录的执行权限。
假设以下目录结构:
drwxrwxrwt. 10 root root 12288 Mar 14 04:31 .
dr-xr-xr-x. 24 root root 4096 Dec 6 03:33 ..
drwx------ 4 root root 4096 Mar 14 04:03 jen
Run Code Online (Sandbox Code Playgroud)
以非 root 用户身份运行以下命令:
find -type d
Run Code Online (Sandbox Code Playgroud)
输出是:
.
./jen
find: `./jen': Permission denied
Run Code Online (Sandbox Code Playgroud)
所以find
找到目录jen并输出。然后它试图下降到jen,但没有许可,所以它打印了错误。上面的第一行打印到stdout
,第二行打印到stderr
。
现在以非 root 用户身份运行以下命令:
find -depth -type d
Run Code Online (Sandbox Code Playgroud)
输出是:
find: `./jen': Permission denied
.
Run Code Online (Sandbox Code Playgroud)
因此,stdout
除非用户具有列出目录内容的权限,否则不会输出路径名。
这个输出非常适合我想做的事情。但是,我不确定这是否只是巧合。我可以依赖这种行为吗?
我正在使用 GNU findutils 4.4.2。我想知道所有版本的find …
find ×2
shell ×2
bash ×1
directory ×1
path ×1
patterns ×1
permissions ×1
portability ×1
scripting ×1
shell-script ×1