`set -e` 和 `grep` 习惯用法,用于防止在未找到模式时过早退出 shell 脚本

`set -e` 和 `grep` 习惯用法,用于防止在未找到模式时过早退出 shell 脚本

需要帮助 - 在 GNU/LINUX bash 上的 shell 脚本环境中:

我总是用set -e.通常,我希望grep但并不总是希望脚本在grep退出状态1指示未找到模式时终止执行。

我尝试解决这个问题的方法如下:

(尝试 I)
如果set +o pipefail并用类似的东西调用 grepgrep 'p' | wc -l那么我会得到所需的行为,直到未来的维护者启用pipefail。另外,我喜欢启用,pipefail所以这对我不起作用。

(尝试二)
使用sedawk仅打印与模式匹配的行,然后使用wc匹配的行来测试匹配的模式。我不喜欢这个选项,因为使用sedtogrep似乎是解决我真正问题的方法。

(尝试 III)
这是我最不喜欢的 - 类似于:set +e; grep 'p'; set-e

任何见解/习语将不胜感激 - 谢谢。

答案1

您可以将 grep 置于if条件中,或者如果您不关心退出状态,请添加|| true.

示例:grep杀死 shell

$ bash
$ set -e
$ echo $$
33913
$ grep foo /etc/motd
$ echo $$
9233

解决方案1:丢弃非零退出状态

$ bash
$ set -e
$ echo $$
34074
$ grep foo /etc/motd || true
$ echo $$
34074

解决方案 2:显式测试退出状态

$ if ! grep foo /etc/motd; then echo not found; fi
not found
$ echo $$
34074

从 bash 手册页讨论set -e

如果失败的命令是紧跟在命令列表中的一部分,则 shell 不会退出尽管或者直到 关键字,测试的一部分如果或者埃利夫保留字,任何命令中执行的一部分 &&或者列出最后一个命令之后的命令除外&&或者,管道中除最后一个命令之外的任何命令,或者命令的返回值与

答案2

要禁用命令失败时的效果errexit,正如其他人所说,将该命令用作条件语句的一部分就足够了,无论是在if/elifthen、或while/untildo或 后跟&&||逻辑运算符之间。

errexit在不更改退出状态的情况下禁用该效果的规范习惯用法是:

cmd && true

那仍然返回虚假的ifcmd失败但不退出 shell。

但通常情况下,您想要的只是忽略失败及其errexit影响。

因此,更规范的方法是:

cmd || true

哪个返回特鲁伊无论cmd成功与否。

grep回报特鲁伊如果任何输入中至少有一行匹配并且没有发生错误并且虚假的否则。

它通常用于:

if grep -q pattern file; then
  echo at least one line of file matched the pattern
  do-something
fi

如果您想要的只是 if any 的输出grep,而不关心是否没有匹配,您可以忽略 的grep退出状态:

grep pattern file || true

但你不会抓住错误例如当file无法打开或正则表达式中存在语法错误或grep无法写入其输出时。

grep1对于不匹配和错误,将使用退出状态,如果未找到,2shell 可能会设置$?为 127 ,如果被杀死,则 shell 可能会设置为大于 128 的数字。grep因此,您应该能够根据 的值来消除不匹配和错误之间的歧义$?,并且errexit仅使用以下内容来触发错误:

grep pattern file || [ "$?" -eq 1 ]

哪个返回特鲁伊如果grep成功或者没有匹配,但是会因为失败而退出errexit[除了不匹配之外的错误)$?1

不过,通常建议进行适当的错误处理,而不是依赖于非常不稳定的错误set -o errexit(又名set -e)。如果您需要区分 的不同故障模式grep,您可以这样做:

die() { [ "$#" -eq 0 ] || printf>&2 '%s\n' "$@"; exit 1; }
grep pattern file
case $? in
  (0) echo OK, match;;
  (1) echo OK, no match;;
  (*) handle-error; die;;
esac

答案3

pipefail您也可以使用子 shell暂时禁用或忽略该设置。

( set +o pipefail ; grep 'p' ) | wc -l

或者

( grep 'p' || true ) | wc -l

另外,请注意|比 结合得更紧密||,因此第二种情况中的括号是必需的。

答案4

关心退出状态时的另一个选择:

    FOUND=$(grep whatever here) || true     
    if [ -z $FOUND ]; then
      echo "not found"
    else
      echo "found"
    fi

相关内容