4

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

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

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

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

谢谢!

4

2 回答 2

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减号前有空格)。

于 2014-07-07T16:59:34.837 回答
1

所有这些示例都只使用内置函数,并且完全兼容dash.

查找子字符串

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

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

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

例如,如果您想$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
}
于 2014-07-23T23:20:09.110 回答