在没有Bashisms的Shell中检查子字符串

时间:2014-07-07 16:55:43

标签: regex linux shell dash-shell

我正在尝试编写一个shell脚本,在其中我必须在字符串中查找 -32 的存在。不幸的是,我不必使用任何bashisms,因为它必须在运行Dash的计算机上运行。

我试过了case ${1+"$@"} in *-32*);;,但是会选择 -321 之类的东西。有没有办法使用正则表达式或其他东西来寻找那个标志?它周围可以有其他标志,用字符串中的空格分隔。

我认为我需要的正则表达式用后面的空格或行尾来查找-32。 -32(\s|$)

我对正则表达式很陌生,所以我不确定这是否是最好的方法。任何帮助将不胜感激!

谢谢!

2 个答案:

答案 0 :(得分:3)

您可以将grep与字边界结合使用:

grep -E '-32\b' FILE

\b匹配'字边界'=字母数字字符和非字母数字字符之间的位置。

在默认语言环境中,“字母数字字符”(如上面使用的术语)表示与字符类[a-zA-Z0-9_]匹配的任何字符(即任何数字,任何字母A-Z和下划线) )。

以类似的方式\B匹配字边界的任何地方(即任何一侧的字符属于同一类型的任何位置,或两个字母数字字符,或两者都是非字母数字的。)

因此,如果您想确保减号必须在之前由非字母数字字符(例如空格),您还可以编写以下内容:

grep -E '\B-32\b' FILE

这将匹配xx -32 xx(减号前的空格)但 xx-32 xx(没有空格)。由于空格和减号都是非字母数字\B,它们之间会匹配,但\b则不会。

如果您想确保减号前面有一个字母数字字符,您可以写下以下内容:

grep -E '\b-32\b' FILE

哪个匹配,例如x-32 x(没有空格),但不是x -32 x(在减号前有空格)。

答案 1 :(得分:1)

所有这些示例仅使用 内置函数,并且与dash完全兼容。

查找子字符串

如果您实际上在寻找字符串的子字符串,可以使用caseif

让我通过使用每个函数编写两个不同的match函数来说明。如果你很懒,你可以将这些函数中的任何一个剪切/粘贴到你的脚本中并使用:

if match -32 "$STRING"; then
    echo "found '-32'!"
fi

E.g。如果你想在开头和结尾搜索$SUBSTR,并用空格与字符串的其余部分分开,你可以使用这样的东西:

function match() {
    local SUBSTR="$1" STR="$2"                # get args
    case " $STR " in                          #   add extra spaces
        *" $SUBSTR "*) return 0 ;;            #   return true if match
    esac
    return 1                                  # no match: return false
}

(在上面的函数中,我在$STR周围添加空格,所以我不必在字符串的开头和结尾显式查找匹配项。)

function match() {
    local SUBSTR=" $1 " STR=" $2 "            # get args + add extra spaces
    [ "${STR#*"$SUBSTR"}" != "$STR" ] \
        && return 0                           # match: return true
    return 1                                  # no match: return false
}

这个if声明有点棘手。表达式${STR#*"$SUBSTR"}表示$STR,并从中删除所有内容,直至第一次出现$SUBSTR(如果找不到$SUBSTR,不要删除任何东西)。然后我们将其与原始$STR进行比较,如果它们相同,我们就知道找到了子字符串。

查找参数

现在,如果您实际上正在寻找一个参数,您可以使用上述任何函数,然后只使用match "-32" "$*",但会找到所有子字符串,而不是将参数彼此区分(例如在不太可能的情况下,任何参数(如文件名)都发生在包含字符串'-32'以匹配)。

在这种情况下,最好只看一下args。我再次为你写一个小功能,你可以用argmatch "$ARG" "$@"

打电话
argmatch() {
    local FIND="$1" ARG; shift               # get $FIND arg, remove it from $@
    for ARG; do                              # loop $@
        [ "$ARG" = "$FIND" ] && return 0     #   found? then return true
    done
    return 1                                 # return false
}