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