在 POSIX sh 中如何判断一个字符串是否包含另一个字符串?

我想编写一个 Unix shell 脚本,如果在另一个字符串中有一个字符串,该脚本将执行各种逻辑。例如,如果我在某个文件夹中,分支。有人能告诉我怎么做吗?如果可能的话,我希望这个命令不是特定于 shell 的(即不仅仅是 bash) ,但是如果没有其他方法的话,我也可以这样做。

#!/usr/bin/env sh


if [ "$PWD" contains "String1" ]
then
echo "String1 present"
elif [ "$PWD" contains "String2" ]
then
echo "String2 present"
else
echo "Else"
fi
325150 次浏览

Bash 正则表达式或者是 expr:

 if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi

遗憾的是,我不知道如何在 sh 中实现这一点。但是,使用 bash (从版本3.0.0开始,可能就是您所拥有的版本) ,您可以像下面这样使用 = ~ 运算符:

#!/bin/bash
CURRENT_DIR=`pwd`


if [[ "$CURRENT_DIR" =~ "String1" ]]
then
echo "String1 present"
elif [[ "$CURRENT_DIR" =~ "String2" ]]
then
echo "String2 present"
else
echo "Else"
fi

作为额外的奖励(和/或警告,如果你的字符串中有任何有趣的字符) ,= ~ 接受正则表达式作为正确的操作数,如果你省略了引号。

请参阅“测试”程序的手册。 如果你只是测试一个目录的存在性,你通常会这样做:

if test -d "String1"; then
echo "String1 present"
end

如果你真的想匹配一个字符串,你也可以使用 bash 展开规则和通配符:

if test -d "String*"; then
echo "A directory starting with 'String' is present"
end

如果需要执行更复杂的操作,则需要使用另一个程序,如 expr。

case $(pwd) in
*path) echo "ends with path";;
path*) echo "starts with path";;
*path*) echo "contains path";;
*) echo "this is the default";;
esac

纯 POSIX 外壳:

#!/bin/sh
CURRENT_DIR=`pwd`


case "$CURRENT_DIR" in
*String1*) echo "String1 present" ;;
*String2*) echo "String2 present" ;;
*)         echo "else" ;;
esac

像 ksh 或 bash 这样的扩展 shell 具有花哨的匹配机制,但是老式的 case却出人意料地强大。

这里还有另一个解决方案,它使用 POSIX 子字符串参数扩展,因此可以在 Bash、 Dash、 KornShell (ksh)、 Z shell (zsh)等中工作。

test "${string#*$word}" != "$string" && echo "$word found in $string"

一个带有一些例子的功能化版本:

# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
string="$1"
substring="$2"
if test "${string#*$substring}" != "$string"
then
return 0    # $substring is in $string
else
return 1    # $substring is not in $string
fi
}


contains "abcd" "e" || echo "abcd does not contain e"
contains "abcd" "ab" && echo "abcd contains ab"
contains "abcd" "bc" && echo "abcd contains bc"
contains "abcd" "cd" && echo "abcd contains cd"
contains "abcd" "abcd" && echo "abcd contains abcd"
contains "" "" && echo "empty string contains empty string"
contains "a" "" && echo "a contains empty string"
contains "" "a" || echo "empty string does not contain a"
contains "abcd efgh" "cd ef" && echo "abcd efgh contains cd ef"
contains "abcd efgh" " " && echo "abcd efgh contains a space"
#!/usr/bin/env sh


# Searches a subset string in a string:
# 1st arg:reference string
# 2nd arg:subset string to be matched


if echo "$1" | grep -q "$2"
then
echo "$2 is in $1"
else
echo "$2 is not in $1"
fi
test $(echo "stringcontain" "ingcon" |awk '{ print index($1, $2) }') -gt 0 && echo "String 1 contain string 2"

输出: 字符串1包含字符串2

如果你只想要一个像“ test”一样快的 谢谢方法,你可以这样做:

contains() # haystack needle
{
haystack=${1/$2/}
if [ ${#haystack} -ne ${#1} ] ; then
return 1
fi
return 0
}

它的工作原理是删除干草堆中的针,然后比较新旧干草堆的绳子长度。

这里是一个 链接的各种解决方案,你的问题。

这是我最喜欢的,因为它最具有人类可读性:

星型通配符方法

if [[ "$string" == *"$substring"* ]]; then
return 1
fi
return 0

在特殊情况下,如果希望查找一个单词是否包含在长文本中,可以使用循环遍历长文本。

found=F
query_word=this
long_string="many many words in this text"
for w in $long_string; do
if [ "$w" = "$query_word" ]; then
found=T
break
fi
done

这是纯粹的谍影重重。

这是基于 这个答案的另一种可能的 POSIX 解决方案,但是要使用特殊字符,如 []*。这是围绕 substring变量用双引号实现的。

这是 另一个线索上的另一个答案的一个替代实现,只使用 shell 内置函数。如果 string是空的,那么最后一个 test会给出一个假阳性,因此我们需要测试在这种情况下 substring是否也是空的。

#!/bin/sh
# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
string="$1"
substring="$2"
test -n "$string" || test -z "$substring" && test -z "${string##*"$substring"*}"
}

或者一句俏皮话:

contains() { test -n "$1" || test -z "$2" && test -z "${1##*"$2"*}"; }

尽管如此,使用 case 就像这个答案一样的解决方案看起来更简单,更不容易出错。

#!/bin/sh
contains() {
string="$1"
substring="$2"
case "$string" in
*"$substring"*) true ;;
*) false ;;
esac
}

或者一句俏皮话:

contains() { case "$1" in *"$2"*) true ;; *) false ;; esac }

为了测试:

contains "abcd" "e" || echo "abcd does not contain e"
contains "abcd" "ab" && echo "abcd contains ab"
contains "abcd" "bc" && echo "abcd contains bc"
contains "abcd" "cd" && echo "abcd contains cd"
contains "abcd" "abcd" && echo "abcd contains abcd"
contains "" "" && echo "empty string contains empty string"
contains "a" "" && echo "a contains empty string"
contains "" "a" || echo "empty string does not contain a"
contains "abcd efgh" "cd ef" && echo "abcd efgh contains cd ef"
contains "abcd efgh" " " && echo "abcd efgh contains a space"


contains "abcd [efg] hij" "[efg]" && echo "abcd [efg] hij contains [efg]"
contains "abcd [efg] hij" "[effg]" || echo "abcd [efg] hij does not contain [effg]"


contains "abcd *efg* hij" "*efg*" && echo "abcd *efg* hij contains *efg*"
contains "abcd *efg* hij" "d *efg* h" && echo "abcd *efg* hij contains d *efg* h"
contains "abcd *efg* hij" "*effg*" || echo "abcd *efg* hij does not contain *effg*"