如何检查字符串是否包含破折号或灰分中的子字符串?

如何检查字符串是否包含破折号或灰分中的子字符串?

这是我正在尝试的:

#!/bin/sh
contains() {
    if $(echo $1 | grep -c $2) ; then
        echo "0" # contains
    else
        echo "1" # not contains
    fi
}

myString=$1
mySubsting=$2

contains $myString '$mySubsting'

下面是一个执行的例子:

# sh ./myScript abcdef bc
./myTest: line 3: 0: command not found
1

编辑:

最初的问题是:如何在 Bourne Shell 中检查字符串是否包含子字符串?

这是我正在尝试的:

  #!/bin/sh
  if echo $1 | grep -q $2
  then
    echo "0"
  else
    echo "1"
  fi

下面是一个执行的例子:

$ sh ./myTest "$(systemctl status ntp)" "Active: active"
grep: active: No such file or directory
1

如何正确检查一个字符串是否包含另一个字符串?

答案1

包含函数的可移植(dash、bash、ksh 等)脚本:

#!/bin/sh

contains() {  if    [ "$1" ] &&            # Is there a source string.
                    [ "$2" ] &&            # Is there a substring.
                    [ -z "${1##*"$2"*}" ]; # Test substring in source.
              then  echo 0;                # Print a "0" for a match.
              else  echo 1;                # Print a "1" if no match.
              fi;
            }

contains "$1" "$2"

其中 0 表示“包含”(真值)。

这将测试为:

 $ contains "test a simple line" simpl
 1

 $ contains "One sentence" "No more"
 0

答案2

Bourne shell 有一个用于此目的的构造。这与现代的相同sh(这看起来更像你正在使用的,Bourne shell 不支持$(...);如果它是 Bourne shell,你会得到一个不同的错误):

case $1 in
  *"$2"*) printf '"%s" is in "%s"\n' "$2" "$1"
esac

如果你想使用grep,那就是:

if printf '%s\n' "$1" | grep -Fqe "$2"; then
  printf '"%s" is in "%s"\n' "$2" "$1"
fi

或者

if grep -Fqe "$2" << EOF
$1
EOF
then
  printf '"%s" is in "%s"\n' "$2" "$1"
fi

$2但只有在不包含换行符的情况下才能正常工作。

无论如何,您都需要对大多数参数扩展进行引号。唯一不需要的地方是上面的地方case $1,但即使那样也case "$1"不会造成伤害。

关于您的代码的一些注释:

  1. 不能用于echo任意字符串。在这里,根据实现的不同,对于like或echo的值,它会失败。$1-nfoo\bar
  2. 在 shell 中,不加引号的参数扩展具有非常特殊的含义。你不想那样做。例如,尝试使用like或grep -c $2的值。$2*root /etc/passwd
  3. grepwithout-F用于正则表达式匹配。您需要-F固定字符串(子字符串)搜索(过去与fgrep),但如果$2包含多行,则再次说明grep -F要搜索任何输入中这些行的内容(grep -F $'a\nb'将查找aor b,而不是$'a\nb'字符串)。
  4. 在 中grep -c $2,如果以 开头,则 的内容$2将被视为选项-。你想要grep -c -e "$2"grep -c -- "$2"避免这种情况。
  5. 您想使用退出状态而不是标准输出来报告布尔条件。在脚本中,用exit(exit 0表示 true,exit 1(或任何非零数字,但避免大于 120 的值)表示 false)。对于函数,请return改为使用。尽管脚本和函数都将返回上次运行命令的状态。
  6. $(cmd) 扩大的输出cmd(并且由于再次缺少引号而在此处经历 split+glob)减去尾随换行符。所以如果cmd输出0\n,$(cmd)扩展为0.因此,运行$(cmd)尝试运行名为 的命令0。如果您想将 的输出转换cmd为退出状态(因此它可以用作布尔值),您需要(exit "$(cmd)").这会启动一个子 shell,该子 shell 会以 的输出cmd作为退出代码退出)。
  7. grep -c计算出现的次数。在这里,您不需要完整的计数,您只需要知道是否找到它(如果至少有一个匹配项)。因为这样grep -q更有效,因为它在找到一个后就停止搜索。对于grep不支持(标准)-q选项的古老实现,您可以使用fgrep -le "$2" > /dev/null.对于-lfgrep也会在第一个匹配时停止,但输出文件名(我们在这里通过将输出重定向到 来丢弃该文件名/dev/null)。

答案3

bash 本身支持这一点;

$ string1="abcmoocow"
$ string2="moo"
$ if [[ $string1 == *$string2* ]]; then echo "Match"; else echo "No Match"; fi
Match
$ string1="abccrowcow"
$ if [[ $string1 == *$string2* ]]; then echo "Match"; else echo "No Match"; fi
No Match

还要纠正你的例子;改变;

if $(echo $1 | grep -c $2) ; then

成为:

if [ -n "$(echo $1 | grep -c $2)" ]; then

(检查 grep 是否返回任何数据)

另请注意,也可以使用退出代码;

$ echo bob | grep "o" &>/dev/null; echo $?
0
$ echo bob | grep "z" &>/dev/null; echo $?
1

相关内容