167

我正在编写一个 shell 脚本,我正在尝试检查命令的输出是否包含某个字符串。我想我可能必须使用 grep,但我不确定如何。有人知道吗?

4

5 回答 5

203

测试$?一种反模式。

if ./somecommand | grep -q 'string'; then
  echo "matched"
fi
于 2015-07-02T22:48:57.690 回答
161

测试grep的返回值:

./somecommand | grep 'string' &> /dev/null
if [ $? == 0 ]; then
   echo "matched"
fi

习惯上是这样完成的:

if ./somecommand | grep -q 'string'; then
   echo "matched"
fi

并且:

./somecommand | grep -q 'string' && echo 'matched'
于 2013-06-05T03:55:15.717 回答
11

另一种选择是检查命令输出上的正则表达式匹配。

例如:

[[ "$(./somecommand)" =~ "sub string" ]] && echo "Output includes 'sub string'"
于 2019-07-18T20:54:34.483 回答
10

一个干净的 if/else 条件 shell 脚本:

if ./somecommand | grep -q 'some_string'; then
  echo "exists"
else
  echo "doesn't exist"
fi
于 2019-12-25T15:09:44.827 回答
3

简短的回答

以上所有(非常优秀的)答案都假设grep可以“看到”命令的输出,这并不总是正确的:

SUCCESS可以发送到STDOUT,而FAILURE可以发送到STDERR

因此,根据您测试的方向,您grep可能会失败。也就是说,如果您正在测试FAILURE2>&1的情况,则必须在这种情况下使用将命令的输出重定向到 STDOUT 。

带证明的更长答案

我在 bash 脚本中使用了我认为非常简单的测试,grep但它一直失败。随之而来的是许多挠头。在我的脚本中使用set -x发现变量是空的!所以我创建了以下测试来了解事情是如何破坏的。

注意iscsiadm是“ open-iscsi ”包中的一个 Linux 工具,用于将主机连接/断开连接到 SAN 存储。该命令iscsiadm -m session用于显示是否建立了任何 LUN 连接):

#!/bin/bash

set -x

TEST1=$(iscsiadm -m session)
TEST2=$(iscsiadm -m session 2>&1)
echo
echo 'Print TEST1'
echo $TEST1
echo
echo 'Print TEST2'
echo $TEST2
echo

如果连接了 LUN ,则两个变量都已成功填充值:

Print TEST1
tcp: [25] 192.168.X.XX:3260,1 iqn.2000-01.com.synology:ipdisk.Target-LUN1 (non-flash) tcp: [26] 192.168.X.XX:3260,1 iqn.2000-01.com.synology:storagehost.Target-LUN1 (non-flash)

Print TEST2
tcp: [25] 192.168.X.XX:3260,1 iqn.2000-01.com.synology:ipdisk.Target-LUN1 (non-flash) tcp: [26] 192.168.X.XX:3260,1 iqn.2000-01.com.synology:storagehost.Target-LUN1 (non-flash)

但是,如果 LUN连接,iscsiadm则将输出发送到 STDERR,并且只有“ TEST2 ”变量填充了我们使用2>&1;重定向到 STDOUT 的位置。没有重定向到 STDOUT 的“ TEST1 ”变量为空:

iscsiadm: No active sessions.

Print TEST1


Print TEST2
iscsiadm: No active sessions.

结论

如果你有一个时髦的、半损坏的——在一个方向上工作但在另一个方向上没有——像这样的情况,试着iscsiadm用你自己的命令替换上面的测试,你应该得到适当的可见性来重写你的测试以使其正常工作。

于 2021-11-15T13:55:54.270 回答