在 shell IF 语句中将关系运算符与 grep -q 结合使用?

在 shell IF 语句中将关系运算符与 grep -q 结合使用?

我找不到这个问题的答案 - 如果是重复的,我深表歉意。

/bin/sh在 BSD 上使用(不是bash!),我正在尝试找出以下 IF 语句的语法。

我有两个组成条款。作为单独的语句编写,它看起来像这样:

if [ "$a" == "y" -o "$a" == "Y" ]; then
    if printf '%s' "$b" | grep -qE 'SOME_REGEX'; then
        # both conditions met: do stuff
    fi
fi

所以我可以使用嵌套if作为解决方法。

但是我需要什么语法才能将它们整齐地组合成一个“if”语句?

注意:如果这个 shell 允许直接正则表达式匹配比较([ "$a" =~ REGEX" ]或类似的)而不是 require grep -q,那么知道这一点很有用,但我仍然想知道如何正确地组合这些子句,因为有一天我肯定会拥有我匹配文件内容而第二条语句类似的情况ls -l "$b" | grep -qE 'SOME_REGEX',因此内联正则表达式比较不起作用...:)

答案1

我个人认为这里有一个嵌套语句是可以的if,尽管我会使用稍微现代化的语法:

if [ "$a" = "y" ] || [ "$a" = "Y" ]; then
    if printf '%s' "$b" | grep -qE 'SOME_REGEX'; then
        # both conditions met: do stuff
    fi
fi

(注意这==是一个bash-ism)

将它们组合起来(恕我直言,使其可读性较差):

if [ "$a" = "y" ] || [ "$a" = "Y" ] && printf '%s' "$b" | grep -qE 'SOME_REGEX'; then
    # both conditions met: do stuff
fi

为了基本的正则表达式,你可以使用expr(参见下面是 Stéphane Chazelas 的评论):

if [ "$a" = "y" ] || [ "$a" = "Y" ] && expr "$b" : 'SOME_REGEX' >/dev/null; then
    # both conditions met: do stuff
fi

shell/bin/sh通常不需要[[ ... =~ ... ]]进行扩展的正则表达式匹配。


关于最后的注释:正则表达式用于跨单行匹配文本。如果将文件名视为文本,则会自动取消任何不是单行文本的文件名的资格,例如包含换行符的文件名。如果您需要对文件名应用正则表达式匹配,请谨慎对待存储在数组 ( $@in ) 中的名称,或者使用支持谓词/bin/sh的实现 。find-regex

文件名通配模式用于匹配文件名。

答案2

请注意,grep匹配输入的每一行,而不是整个输入,因此通常不适合任意字符串。您可以使用awk它来代替(注意那是扩展正则表达式类似于grep -Eorbash的理解[[ string =~ regexp ]])。

regexp_match() {
  awk 'BEGIN{if (ARGV[1] !~ ARGV[2]) exit(1)}' "$@"
}

if [ "$a" = y ] || [ "$a" = Y ] && regexp_match "$b" REGEXP; then
   ...
fi

请注意,应避免使用-a/二元运算符。-o [它们已被 POSIX 弃用,并且存在许多问题。例如,在 FreeBSD 上:

$ a='(' /bin/sh -c '[ "$a" = y -o "$a" = Y ]'
[: closing paren expected

答案3

您可以通过连接$a并向$b正则表达式添加模式来缩短它

 if printf '%s%s\n' "$a" "$b" | grep -qE '^[yY]SOME_REGEX'; then

请注意,grep 是行匹配工具,因此 \n 位于末尾

相关内容