为什么使用grep "-c"并且计数为0时,程序会以状态码-1退出?

8
grep -c返回0时,脚本为什么会以“-1”退出代码失败。只有在设置了set -o errexit时才会发生这种情况。
在bash shell中进行复制/粘贴
cat <<'EOT' > /tmp/foo.sh
#!/usr/bin/env bash

function bash_traceback() {
  local lasterr="$?"
  set +o xtrace
  local code="-1"
  local bash_command=${BASH_COMMAND}
  echo "Error in ${BASH_SOURCE[1]}:${BASH_LINENO[0]} ('$bash_command' exited with status $lasterr)"
  if [ ${#FUNCNAME[@]} -gt 2 ]; then
    # Print out the stack trace described by $function_stack
    echo "Traceback of ${BASH_SOURCE[1]} (most recent call last):"
    for ((i=0; i < ${#FUNCNAME[@]} - 1; i++)); do
    local funcname="${FUNCNAME[$i]}"
    [ "$i" -eq "0" ] && funcname=$bash_command
    echo -e "  $i: ${BASH_SOURCE[$i+1]}:${BASH_LINENO[$i]}\t$funcname"
    done
  fi
  echo "Exiting with status ${code}"
  exit "${code}"
}

test_redirecting_of_stdout_stderr() {

    # Exit program when error found
    set -o errexit

    # Exit program when undefined variable is being used
    set -o nounset

    local up_count
    up_count=$(ls | grep -c NOTHING_MATCHED)
    echo "up_count: $up_count"
}

# provide an error handler whenever a command exits nonzero
trap 'bash_traceback' ERR

set -o errtrace

test_redirecting_of_stdout_stderr

EOT

bash /tmp/foo.sh

输出

debian:~/my-mediawiki-docker$ bash /tmp/foo.sh
Error in /tmp/foo.sh:31 ('up_count=$(ls | grep -c NOTHING_MATCHED)' exited with status 255)
Traceback of /tmp/foo.sh (most recent call last):
  0: /tmp/foo.sh:31     up_count=$(ls | grep -c NOTHING_MATCHED)
  1: /tmp/foo.sh:40     test_redirecting_of_stdout_stderr
Exiting with status -1
debian:~/my-mediawiki-docker$

1
让我回应chepner提供的链接[BashFAQ#105](http://mywiki.wooledge.org/BashFAQ/105)。 - Charles Duffy
(顺便说一句,如果您使用 printf ' %s: %s:%s\t%s\n' "$i" "${BASH_SOURCE[$i+1]}" "${BASH_LINENO[$i]}" "$funcname" 而不是 echo -e,则可以更可靠地在更广泛的有效 bash 运行时配置中工作。) - Charles Duffy
2个回答

7

grep 报告“失败”,如果它未能找到任何匹配的行。这里是 man grep

EXIT STATUS
       The exit status is 0 if selected lines are found, and 1 if not found. 

如果您想要允许一个命令以非零值退出而不中断脚本在 errexit 模式下,可以使用 || true:
up_count=$(ls | grep -c NOTHING_MATCHED) || true

在这种用法中,“:`”是“true”的同义词,因此,人们经常会看到“foo ||:”具有相同的作用。 - Charles Duffy

4

设置此选项意味着,从命令中得到任何非零退出状态都被视为致命错误。这在grep中并不是这种情况,它使用非零退出状态仅表示未匹配成功。这使您可以编写如下代码:

if grep "$pattern" file.txt; then
    echo "Found a match"
else
    echo "Found no match"
fi
if command; then ... errexit特别忽略在类似上面的if条件中使用的命令的退出状态,但无法知道像if command; then ...这样的行。请注意保留HTML标记。
up_count=$(ls | grep -c NOTHING_MATCHED)

允许命令出现非零退出状态。解决方法是使用保护这些命令的方式。

# As an aside, see http://mywiki.wooledge.org/ParsingLs
up_count=$(ls | grep -c NOTHING_MATCHED) || :

一般情况下,自己进行错误检查比依赖于errexit更好;有关更多信息,请参见http://mywiki.wooledge.org/BashFAQ/105


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接