我正在研究这个preinst文件的内容,该脚本在包从Debian归档文件(.deb)文件解压缩之前执行该文件。

脚本代码如下:

#!/bin/bash
set -e
# Automatically added by dh_installinit
if [ "$1" = install ]; then
   if [ -d /usr/share/MyApplicationName ]; then
     echo "MyApplicationName is just installed"
     return 1
   fi
   rm -Rf $HOME/.config/nautilus-actions/nautilus-actions.conf
   rm -Rf $HOME/.local/share/file-manager/actions/*
fi
# End automatically added section

我的第一个问题是关于这一行的:

set -e

我认为脚本的其余部分非常简单:它检查Debian/Ubuntu包管理器是否正在执行安装操作。如果是,它将检查我的应用程序是否刚刚安装到系统上。如果有,脚本打印消息“MyApplicationName刚刚安装”并结束(返回1意味着以“错误”结束,不是吗?)

如果用户要求Debian/Ubuntu包系统安装我的包,脚本还会删除两个目录。

是这样吗,还是我漏掉了什么?


当前回答

根据bash - Set Builtin手册,如果设置了-e/errexit,当由单个简单命令、列表或复合命令组成的管道返回非零状态时,shell立即退出。

默认情况下,管道的退出状态是管道中最后一个命令的退出状态,除非启用了pipefail选项(默认情况下禁用)。

如果是,最后一个(最右边)退出命令的管道返回状态为非零状态,如果所有命令都成功退出,则为零。

如果你想在退出时执行一些东西,尝试定义trap,例如:

trap onexit EXIT

其中onexit是你的函数,在退出时做一些事情,如下所示,打印简单的堆栈跟踪:

onexit(){ while caller $((n++)); do :; done; }

还有类似的选项-E/errtrace,它会捕获ERR,例如:

trap onerr ERR

例子

零状态示例:

$ true; echo $?
0

非零状态示例:

$ false; echo $?
1

否定地位的例子:

$ ! false; echo $?
0
$ false || true; echo $?
0

禁用pipefail测试:

$ bash -c 'set +o pipefail -e; true | true | true; echo success'; echo $?
success
0
$ bash -c 'set +o pipefail -e; false | false | true; echo success'; echo $?
success
0
$ bash -c 'set +o pipefail -e; true | true | false; echo success'; echo $?
1

启用pipefail测试:

$ bash -c 'set -o pipefail -e; true | false | true; echo success'; echo $?
1

其他回答

我相信这样做的目的是为了让这个剧本迅速失败。

要亲自测试,只需在bash提示符下键入set -e。现在,试着运行ls。您将得到一个目录列表。现在输入lsd。该命令无法识别,并将返回一个错误代码,因此bash提示符将关闭(由于set -e)。

现在,为了在“脚本”的上下文中理解这一点,使用这个简单的脚本:

#!/bin/bash 
# set -e

lsd 

ls

如果按原样运行,您将从最后一行的ls中获得目录列表。如果取消set -e的注释并再次运行,则不会看到目录列表,因为bash一旦遇到来自lsd的错误就会停止处理。

Script 1: without setting -e
#!/bin/bash
decho "hi"
echo "hello"
This will throw error in decho and program continuous to next line

Script 2: With setting -e
#!/bin/bash
set -e
decho "hi" 
echo "hello"
# Up to decho "hi" shell will process and program exit, it will not proceed further

set -e该选项指示bash在任何命令[1]的退出状态为非零时立即退出。您可能不想为命令行shell设置这个,但在脚本中它非常有用。在所有广泛使用的通用编程语言中,一个未处理的运行时错误——无论是Java中的抛出异常,还是C中的分段错误,或者Python中的语法错误——都会立即停止程序的执行;后续行不执行。

By default, bash does not do this. This default behavior is exactly what you want if you are using bash on the command line you don't want a typo to log you out! But in a script, you really want the opposite. If one line in a script fails, but the last line succeeds, the whole script has a successful exit code. That makes it very easy to miss the error. Again, what you want when using bash as your command-line shell and using it in scripts are at odds here. Being intolerant of errors is a lot better in scripts, and that's what set -e gives you.

复制自:https://gist.github.com/mohanpedala/1e2ff5661761d3abd0385e8223e16425

这可能对你有帮助。

cat a.sh
#! /bin/bash

#going forward report subshell or command exit value if errors
#set -e
(cat b.txt)
echo "hi"

./a.sh; echo $?
cat: b.txt: No such file or directory
hi
0

当set -e被注释掉时,我们看到echo "hi"退出状态被报告,hi被打印出来。

cat a.sh
#! /bin/bash

#going forward report subshell or command exit value if errors
set -e
(cat b.txt)
echo "hi"

./a.sh; echo $?
cat: b.txt: No such file or directory
1

现在我们看到b.txt错误被报告,没有打印hi。

因此shell脚本的默认行为是忽略命令错误并继续处理并报告最后一个命令的退出状态。如果你想退出错误并报告它的状态,我们可以使用-e选项。

如果命令或管道出现错误,Set -e将停止脚本的执行——这与默认shell行为相反,默认shell行为是忽略脚本中的错误。在终端中键入help set以查看此内置命令的文档。