$(命令)$?附加退出代码

$(命令)$?附加退出代码

几天前我开始学习 Bash。

我正在尝试将表达式的退出状态获取grep到变量中,如下所示:

check=grep -ci 'text' file.sh

我得到的输出是

No command '-ic' found

我应该使用管道命令来执行此操作吗?

答案1

你的命令,

check=grep -ci 'text' file.sh

将被 shell 解释为“-ci使用参数text和运行命令file.sh,并将变量设置为其环境中的check值”。grep


shell 将最近执行的命令的退出值存储在变量中?。您可以将其值分配给您自己的变量之一,如下所示:

grep -i 'PATTERN' file
check=$?

如果你想根据这个值采取行动,你可以使用你的check变量:

if [ "$check" -eq 0 ]; then
    # do things for success
else
    # do other things for failure
fi

或者您可以跳过使用单独的变量并必须$?一起检查:

if grep -q -i 'pattern' file; then
  # do things (pattern was found)
else
  # do other things (pattern was not found)
fi

(请注意-q,它指示grep不输出任何内容并在匹配时立即退出;我们对这里的匹配内容并不真正感兴趣)

或者,如果您只想在模式出现时“做事”不是成立:

if ! grep -q -i 'pattern' file; then
  # do things (pattern was not found)
fi

$?仅当您稍后需要使用它时,当 in 中的值$?已被覆盖时,才需要保存到另一个变量中,如

mkdir "$dir"
err=$?

if [ "$err" -ne 0 ] && [ ! -d "$dir" ]; then
    printf 'Error creating %s (error code %d)\n' "$dir" "$err" >&2
    exit "$err"
fi

在上面的代码片段中,$?将被测试结果覆盖[ "$err" -ne 0 ] && [ ! -d "$dir" ]。仅当我们需要显示它并将其与 一起使用时才需要将其保存在这里exit

答案2

check=grep您已告诉 bash在传递给命令的环境中设置变量

-ci 'text' file.sh

ci不存在。

我相信您的意思是将该命令括在反引号中,或者放在前面有美元符号的括号中,其中任何一个都会分配在文件中找到“文本”的行数(不区分大小写):

check=`grep -ci 'text' file.sh`

check=$(grep -ci 'text' file.sh)

如果没有匹配,现在$check应该为 0,如果有任何匹配,则应该为正。

答案3

您的问题不清楚,但根据您提交的代码,您似乎希望变量check存储grep命令的退出状态。执行此操作的方法是运行

grep -ci 'text' file.sh
check=$?

从 shell 运行命令时,可以通过特殊的 shell 参数 来获取其退出状态$?

POSIX(类 Unix 操作系统的标准)在其文档中记录了这一点外壳规格Bash 的实现记录在特殊参数

由于您是新学习者,我强烈建议您从一本好书和/或在线教程开始学习基础知识。 Stack Exchange 网站上不鼓励推荐外部资源,但我建议Lhunath 和 GreyCat 的 Bash 指南

答案4

其他答案阐明了您的命令不起作用的原因,以及有关如何测试其结果的一些很好的建议。我想再补充一点。

$(命令)$?附加退出代码

您可以使用命令替换和退出代码检查的组合来完成此操作,全部在一行中完成。它将把退出代码作为数字附加到输出中。

check=$( grep -ci 'text' file.sh )$?

这实际上是$(some command)(获取命令的字符串输出)紧随其后的是$?(获取最后一个命令的退出代码)。为了工作,它们必须一起使用,没有空间。

来源:https://www.assertnotmagic.com/2018/06/20/bash-brackets-quick-reference/#-dollar-single-parentheses-dollar-q-

如果有任何输出的可能性(大多数命令都是这种情况),则必须使用 抑制它> /dev/null 2>&1

如果您使用诸如 之类的测试命令,这可能不是必需的test -d <directory>

check=$( grep -ci 'text' file.sh > /dev/null 2>&1)$?

您可以使用一个函数来抽象它:

e() {
    $@ > /dev/null 2>&1
}

# Usage:
check=$(e grep -ci 'text' file.sh)$?

测试退出代码

要稍后使用它,请针对零进行测试(成功):

[ $check -eq 0 ] && echo "passed" || echo "didn't pass"

[ $check -ne 0 ] && echo "didn't pass" || echo "passed"

使用 if/then/else 结构,针对零进行测试(成功):

if [ $check -eq 0 ]; then
    echo "passed"
else
    echo "didn't pass"
fi

if [ $check -ne 0 ]; then
    echo "didn't pass"
else
    echo "passed"
fi

直接测试退出代码

在子 shellexit中使用将根据您可以直接使用的数字生成正确的退出代码:()

(exit $check) && echo "check passed" || echo "check didn't pass"

! (exit $check) && echo "check didn't pass" || echo "check passed"

使用 if/then/else 结构,直接使用退出代码:

if (exit $check); then
    echo "passed"
else
    echo "didn't pass"
fi

if ! (exit $check); then
    echo "didn't pass"
else
    echo "passed"
fi

使用return代替exit也可以在某些 shell 中工作 - 包括 zsh(但不是 bash)。

变得花哨

如果您想进一步简化,请使用此函数:

t() { return $1; }

现在你可以这样测试:

t $check && echo "passed" || echo "didn't pass"

! t $check && echo "didn't pass" || echo "passed"

相关内容