通过 grep 验证时遇到问题

通过 grep 验证时遇到问题
list="feature test release"
branch=feature/fix

我正在尝试检查分支名称是否不以列表中的任何前缀开头,然后退出命令。如果分支具有列表中的前缀之一,则有效。

 echo $list| grep -e "$branch/[a-zA-Z0-9]" ; echo $?

不幸的是这个命令也不起作用。任何想法? ietest/bla是有效的分支名称,但testtest/bla不是

编辑:我正在使用sh,有效前缀列表可以是单个字符串或数组,两者都可用。

答案1

如果您不需要变量中包含有效前缀,则可以使用以下任何解决方案。

根据eg是否feature/foo/bar有效,您必须仅删除最后一个/*或全部。

您可能需要单独的测试来检查是否branch包含 a /

例子check.sh

#!/bin/sh

# foo/bar --> ^foo$
# foo --> ^foo$
# foo/bar/baz --> ^foo$
pattern='^'"${branch%%/*}"'$'

# search for pattern in input, suppress output
grep "$pattern" >/dev/null <<EOF
feature
test
release
EOF

echo $?

测试

$ branch=featur/fix ./check.sh
0
$ branch=foo/fix ./check.sh
1
$ branch=xfeature/fix ./check.sh
1
$ branch=featurex/fix ./check.sh
1

编辑:

正如中提到的斯蒂芬·查泽拉斯branch='.*'' 注释,如果提供的分支名称包含任何正则表达式元字符,例如 for ,上述解决方案可能会产生意外的匹配。

根据要检查的确切值,可以通过将字符串括在分隔字符(例如 )中来避免这种情况/

# ...
pattern="/${branch%%/*}/"
# ...
fgrep "$pattern" >/dev/null <<EOF
/feature/
/test/
/release/
EOF
# ...

例子check2.sh

#!/bin/sh

# removes longest match /*
# foo/bar/baz --> foo
case "${branch%%/*}" in
feature|test|release)
    echo valid 1
    ;;
*)
    echo invalid 1
    ;;
esac

# removes shortedt match /*
# foo/bar/baz --> foo/bar
case "${branch%/*}" in
feature|test|release)
    echo valid 2
    ;;
*)
    echo invalid 2
    ;;
esac

测试

$ branch=feature/fix ./check2.sh
valid 1
valid 2
$ branch=feature/fix/bla ./check2.sh
valid 1
invalid 2
$ branch=xfeature/fix ./check2.sh
invalid 1
invalid 2
$ branch=featurex/fix ./check2.sh
invalid 1
invalid 2

答案2

如果$list是一个包含空格分隔的单词列表的标量变量,并且您想检查它$branch是这些单词之一,后跟/一个或多个 ASCII 算数,在 POSIX 中sh,您可以这样做:

validate() (export LC_ALL=C
  list=$1 branch=$2
  case $branch in
    (*' '*) return 1;;
  esac
  case ${branch##*/} in
    ("" | *[![:alnum:]]*) return 1;;
  esac
  case " $list " in
    (*" ${branch%/*} "*) return 0;;
    (*) return 1;;
  esac
)

进而:

if validate "$list" "$branch"; then
  echo OK
else
  echo KO
fi

要对任意字符串(而不是行)进行正则表达式匹配,POSIXly,主要选项是exprand it's:运算符,尽管它使用基本正则表达式并存在一些设计问题 and awkand it's~运算符(使用扩展正则表达式)。

在这里,您可以这样做(假设中没有一个单词$list是正则表达式运算符):

validate() {
  LC_ALL=C awk -- '
    BEGIN {
      regexp = ARGV[1]
      branch = ARGV[2]
      gsub(" ", "|", regexp)
      regexp = "^("regexp")/[a-zA-Z0-9]+$"
      exit !(branch ~ regexp)
    }' "$@"
}

(这里使用[a-zA-Z0-9]而不是[[:alnum:]]因为您仍然遇到awk不支持 POSIX 字符类的实现)。

需要记住以下几点:

  • grep基于行工作,因此您不能使用它来验证任意字符串,除非您确保这些字符串不包含换行符。
  • 在 POSIX shell 中,参数扩展必须加引号,否则它们将受到 split+glob 的影响(no echo $list
  • echo不能用于输出任意数据,请使用printf(所以echo $list应该是printf '%s\n' "$list")。
  • 像这样的范围0-9A-Za-z只能在 C 语言环境中使用。在 C 语言环境中,[0-9A-Za-z]恰好与 匹配相同的内容[[:alnum:]]

答案3

这是我对 @Bodo 一行版本的评估:

echo $list | tr ' ' '\n' | grep '^'"${branch%%/*}"'$'; if [[ $? -eq 0 ]]; then echo  "VALID NAME"; else echo "NOPE"; exit 1; fi;

答案4

当你这样做时,

list="feature test release"
branch=feature/fix
echo $list| grep -e "$branch/[a-zA-Z0-9]"

(并假设未修改$IFS,因为您忘记引用$list),您实际上是在这样写:

echo feature test release | grep -e 'feature/fix/[a-zA-Z0-9]'

这是在字符串中寻找模式feature/fix/X(对于任何字母数字字符) 。那是行不通的。Xfeature test release

您可以将列表的格式更改为正则表达式,并将您的标签与该标签进行比较

listRE="^($(printf '%s\n' "$list" | tr ' ' '|'))/"    # ^(feature|test|release)/
printf '%s\n' "$branch" | grep -E "$listRE"; echo "$?"

相关内容