我设置了一些 bash 脚本,主要使用
#!/bin/bash
但我经常遇到一些看起来像
#!/bin/bash -e
#!/bin/bash -x
#!/bin/bash -ex
等等。
有人可以解释一下这些 shebang 选项的含义和好处以及它们是否适用于其他 shebang 吗?
答案1
如果脚本/path/to/foo
以 开头#!/bin/bash
,则执行/path/to/foo arg1 arg2
相当于执行/bin/bash /path/too/foo arg1 arg2
。如果 shebang 行是#!/bin/bash -ex
,则执行相当于执行/bin/bash -ex /path/too/foo arg1 arg2
。此功能由内核管理。
请注意,您可以在 shebang 行上移植只有一个参数:一些 unices(例如 Linux)只接受一个参数,因此这#!/bin/bash -e -x
会导致 bash 接收单个五个字符的参数-e -x
(语法错误)而不是两个参数-e
和-x
。
对于 Bourne shellsh
及其派生 shell,例如 POSIX sh、bash、ksh 和 zsh:
-e
意味着如果任何命令失败(通过返回非零状态表示),脚本将立即终止。-x
导致 shell 打印执行跟踪。
其他程序可能理解这些选项,但含义不同。
答案2
它们是传递以bash
查看help set
更多信息的选项,在本例中为:
-x Print commands and their arguments as they are executed.
-e Exit immediately if a command exits with a non-zero status.
答案3
我只想提一个更好的(更便携的)替代方案:
#!/usr/bin/env bash
上面的例子使用env
来查找bash
可执行文件,但并不总是位于/bin/bash
。旧的#!/bin/bash
脚本无法在NixOS, 例如。
如果使用env
如上所示的方式,则无法提供诸如-e
to 之类的参数bash
(据我所知)。但您可以改为这样做:
#!/usr/bin/env bash
set -e
答案4
使用 启动脚本,或者等效地运行 ,与在脚本中紧接着其行后插入具有相同的效果。#! /path/to/bash -option
bash -option /path/to/script
set -option
#!
set -x
本质上只是为了调试;通常你不会希望它一直处于开启状态。
的效果set -e
比手册上说的要复杂得多。更准确的描述大致如下:
调用后
set -e
,如果未经测试命令以非零状态退出,它将导致 shell 以该退出状态退出。
我说更确切因为它仍然很模糊:考虑该命令的情况列表已测试晦涩难懂,难以预测。确切的规则因 shell 而异,甚至同一 shell 的不同版本之间也存在差异。
set -e
做不是导致 Bash 因任何命令的非零退出状态而退出:
- 之间
if
/elif
和then
; 或 - 之间
while
/until
和do
; 或 - 以下
!
;或 - 随后是
||
或&&
或&
(尽管&
相应的wait
或fg
可能会失败);或 - 随后是
|
,除非set -o pipefail
有效;或 $( ... )
当用作命令的一部分时位于内部(不是裸分配和/或重定向,这意味着foo=$( bar )
如果失败将会失败bar
,但local foo=$( bar )
不会);或者- 在适用上述内容的复合命令中;或
- 在从上述适用的任何地方调用的 shell 函数内部。
对复合命令和 shell 函数的影响是递归的。
由于壳层本身以非零状态退出,因此其效果可以传播出子壳层。
!
即使忽略倒置退出状态,豁免仍然适用。
相反,set -e
触发所有其他非零状态,无论它表示“失败”还是简单的“错误”。例如,当初始值为 0((x++))
时,将具有非零“失败”退出状态。x
因为它太混乱了,所以有一派观点认为set -e
应该避免这种情况,而应该明确检查所有命令。
或者如果您仍想使用set -e
,请记住在任何组!
前面写上。((arithmetic))