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,主要选项是expr
and it's:
运算符,尽管它使用基本正则表达式并存在一些设计问题 and awk
and 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
(对于任何字母数字字符) 。那是行不通的。X
feature test release
您可以将列表的格式更改为正则表达式,并将您的标签与该标签进行比较
listRE="^($(printf '%s\n' "$list" | tr ' ' '|'))/" # ^(feature|test|release)/
printf '%s\n' "$branch" | grep -E "$listRE"; echo "$?"