检查命令的输出是否包含shell脚本中的某个字符串

use*_*764 90 bash shell grep

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

mat*_*mat 140

测试$?是一种反模式

if ./somecommand | grep -q 'string'; then
  echo "matched"
fi
Run Code Online (Sandbox Code Playgroud)

  • @VitalyZdanevich,一方面,测试“$?”不会将前面的命令设置为“已检查”以用于“set -e”或“ERR”陷阱,因此您的程序可以在您希望它简单地退出的情况下退出稍后返回故意错误的路径。另一方面,“$?”是不稳定的全局状态——很容易意外地丢弃它的值。例如,如果添加一行类似 `echo "Exit status is $?"` 的日志记录,则 `$?` 中的新值将成为 `echo` 的退出状态。 (4认同)
  • @VitalyZdanevich 我认为是因为它对并发性不强。 (3认同)
  • 为什么测试$?是反模式? (2认同)

per*_*eal 73

测试grep的返回值:

./somecommand | grep 'string' &> /dev/null
if [ $? == 0 ]; then
   echo "matched"
fi
Run Code Online (Sandbox Code Playgroud)

这是惯用的做法:

if ./somecommand | grep -q 'string'; then
   echo "matched"
fi
Run Code Online (Sandbox Code Playgroud)

并且:

./somecommand | grep -q 'string' && echo 'matched'
Run Code Online (Sandbox Code Playgroud)

  • 此外,`grep'字符串'&>/dev/null`都是非POSIX兼容的,并且执行速度要慢得多(如果`string`出现在长输出流的早期),而不是`grep -q string`.[需要注意的是,如果你想确定`somecommand`在发出`string`后继续运行,在这种情况下使用`grep -q` - 通过关闭它的stdin并在看到`string`的第一个实例后退出 - 可能适得其反].(Re:"非POSIX兼容","&>"是一个扩展 - 请参阅http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_07,描述POSIX强制重定向支持) . (4认同)
  • 请注意,关闭的方括号和0之间需要有一个空格.我无法编辑它. (2认同)
  • 此代码不适用于所有POSIX shell:POSIX标准只需要`=`作为比较运算符,而不是`==`; 请参阅http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html (2认同)

Noa*_*nos 11

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

例如:

[[ "$(./somecommand)" =~ "sub string" ]] && echo "Output includes 'sub string'"
Run Code Online (Sandbox Code Playgroud)


F1L*_*nux 10

简短回答

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

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

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

带证据的更长答案

我在 bash 脚本中进行了一个我认为非常简单的测试,grep但它一直失败。接下来是很多令人头疼的事情。在我的脚本中使用set -x显示该变量为空!因此,我创建了以下测试来了解事情是如何发生的。

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

#!/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
Run Code Online (Sandbox Code Playgroud)

如果已连接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)
Run Code Online (Sandbox Code Playgroud)

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

iscsiadm: No active sessions.

Print TEST1


Print TEST2
iscsiadm: No active sessions.
Run Code Online (Sandbox Code Playgroud)

结论

如果您有一个时髦的、半损坏的-在一个方向上工作但在另一个方向上不起作用-诸如此类的情况,请尝试用iscsiadm您自己的命令替换上述测试,您应该获得适当的可见性来重写您的测试以使其正常工作。

  • 这就是我需要的缺失的部分。像 resize2fs 这样的命令需要它(2>&1)。感谢您的澄清! (3认同)

Ehs*_*dar 8

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

if ./somecommand | grep -q 'some_string'; then
  echo "exists"
else
  echo "doesn't exist"
fi
Run Code Online (Sandbox Code Playgroud)