如何在字符串中查找子字符串(或如何使用grep命令搜索变量)?

51
我正在使用BASH,但不知道如何查找子字符串。它一直失败,我有一个字符串(这应该是一个数组吗?)
在下面的代码中,LIST 是一个数据库名称的字符串列表,SOURCE 是回复中的其中一个数据库。以下仍然无法工作:
echo "******************************************************************"
echo "*                  DB2 Offline Backup Script                     *"
echo "******************************************************************"
echo "What's the name of of the  database you would like to backup?"
echo "It will be named one in this list:"
echo ""
LIST=`db2 list database directory | grep "Database alias" | awk '{print $4}'`
echo $LIST
echo ""
echo "******************************************************************"
echo -n ">>> "
read -e SOURCE

if expr match "$LIST" "$SOURCE"; then
    echo "match"
    exit -1
else
    echo "no match"
fi
exit -1

我也尝试过这个方法,但没有效果:

if [ `expr match "$LIST" '$SOURCE'` ]; then

1
不知道LISTSOURCE的样子,很难回答任何问题。 - SiegeX
1
在Bash中,几乎没有理由使用外部实用程序expr - Dennis Williamson
是的,这个解决了:https://dev59.com/znVC5IYBdhLWcg3woStW - edumike
8个回答

89
LIST="some string with a substring you want to match"
SOURCE="substring"
if echo "$LIST" | grep -q "$SOURCE"; then
  echo "matched";
else
  echo "no match";
fi

1
使用这种方法需要考虑两个问题:(1) grep 使用正则表达式,因此某些字符可能会匹配意外或导致错误;(2) 使用 grep(或任何不内置于 bash 的东西)会产生一个单独的进程,这将运行得更慢(只有在大规模情况下才会有影响)。 - codesniffer

38

您还可以使用通配符进行比较:

if [[ "$LIST" == *"$SOURCE"* ]]


7
你应该始终引用字符串,例如:if [[ "$list" == *"$source"* ]] - maganap
1
请注意,if [[ *"$SOURCE"* == "$LIST$" ]] 是假的。 - Leo
我确认顺序很重要/强制性 - 因此 *"$SOURCE"* 必须在正确的位置 - 否则始终返回 false - 为什么会出现这种行为? - Manuel Jordan

8

在Bash中,这可以不用派生外部命令来实现:

function has_substring() {
   [[ "$1" != "${2/$1/}" ]]
}

用法示例:

name="hello/world"
if has_substring "$name" "/"
then
   echo "Indeed, $name contains a slash!"
fi

1
这种解决方案的优点在于它不依赖于任何外部命令或文件描述符(通过重定向或管道)。 - bill.lee
4
注意,这里使用正则表达式来搜索子字符串(还进行了一个不在原位的替换),因此搜索中的特殊字符可能会导致意料之外的结果。但如果正则表达式没问题,为什么不只进行正则表达式搜索呢? 语法示例:if [[“$string” =~ $substring]] - codesniffer

7
如果您正在使用bash,只需输入以下命令:
if grep -q "$SOURCE" <<< "$LIST" ; then
    ...
fi

1

如果您只想查找单个字符,可以使用“index”,例如:

LIST="server1 server2 server3 server4 server5"
SOURCE="3"
if expr index "$LIST" "$SOURCE"; then
    echo "match"
    exit -1
else
    echo "no match"
fi

输出是:
23
match

1
expr match "$LIST" '$SOURCE'

由于该函数搜索 $SOURCE 字符串的开头并返回匹配到的 $SOURCE 字符串后面的位置,如果没有找到则返回0,所以您需要编写另一段代码来解决问题。请注意保留 HTML 标签。
expr match "$LIST" '.*'"$SOURCE" or expr "$LIST" : '.*'"$SOURCE"

表达式$SOURCE必须用双引号括起来,以便解析器可以设置替换。单引号不会进行替换,上面的代码将从$LIST的开头搜索文本字符串$SOURCE。如果需要字符串开头,请减去长度$SOURCE,例如${#SOURCE}。 您也可以编写。
expr "$LIST" : ".*\($SOURCE\)"

这个函数只是从 $LIST 中提取 $SOURCE 并返回它。否则你会得到一个空字符串。但是双引号的问题很棘手。我不知道如何解决它,而不使用额外的变量。 这是一个轻量级的解决方案。所以你可以用 C 语言编写。有一个现成的函数叫做 strstr。 不要使用 expr index,所以非常有吸引力。但是 index 只搜索子串的第一个字符,而不是整个子串。


0

那么,这样的东西怎么样:

PS3="Select database or <Q> to quit: "
select DB in db1 db2 db3; do
   [ "${REPLY^*}" = 'Q' ] && break
   echo "Should backup $DB..."
done

0

表达式使用而不是[内部,变量仅在双引号内扩展,所以请尝试这样做:

if expr match "$LIST" "$SOURCE"; then

但我不是很清楚 SOURCE 应该代表什么。

看起来你的代码将从标准输入读取一个模式,如果匹配数据库别名,则退出,否则它将回显“ok”。这是你想要的吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接