我想编写一个函数来检查给定变量(例如 )是否var
以给定字符串列表中的任何单词开头。这个列表不会改变。
为了实例化,让我们假设我想检查是否var
以aa
,abc
或开头3@3
。
此外,我想检查是否var
包含字符>
。
假设这个函数被称为check_func
.我的预期用途看起来像
if check_func "$var"; then
do stuff
fi
例如,它应该为 、 和aardvark
“abcdef
做一些事情” 。[email protected]
12>5
我见过这个问题用户提供部分工作的情况:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
我的想法是我会迭代上面提到的列表并使用这个函数。我的困难在于不确切地理解应该如何退出(或任何替代返回的方式)才能完成这项工作。
答案1
check_prefixes () {
value=$1
for prefix in aa abc 3@3; do
case $value in
"$prefix"*) return 0
esac
done
return 1
}
check_contains_gt () {
value=$1
case $value in
*">"*) return 0
esac
return 1
}
var='aa>'
if check_prefixes "$var" && check_contains_gt "$var"; then
printf '"%s" contains ">" and starts with one of the prefixes\n' "$var"
fi
我将测试分为两个功能。case ... esac
一旦可以确定,两者都会使用并返回成功(零)。如果没有匹配,则返回失败 (1)。
为了使前缀列表更像是动态列表,可以将第一个函数写为
check_prefixes () {
value=$1
shift
for prefix do
case $value in
"$prefix"*) return 0
esac
done
return 1
}
(要检查的值是第一个参数,我们将其保存在函数的参数列表中value
,然后将其shift
从函数的参数列表中删除;然后我们迭代剩余的参数)然后将其调用为
check_prefixes "$var" aa abc 3@3
第二个函数可以以类似的方式更改为
check_contains () {
value=$1
shift
case $value in
*"$1"*) return 0
esac
return 1
}
(检查某个任意子字符串),或者
check_contains_oneof () {
value=$1
shift
for substring do
case $value in
*"$substring"*) return 0
esac
done
return 1
}
(检查多个子字符串中的任何一个)
答案2
对于bash:
使用正则表达式的属性,您可以start
用^
和contain
不用任何内容来书写。
要检查的正则表达式列表开始与aa
abc
或3@3
和包含 >
是:
^aa ^abc ^3@3 >
使之成为适当地引用列表并要求 bash 使用正则表达式 ( =~
):
check_func() {
matched=1
for test_regex in '^aa' '^abc' '^3@3' '>'; do
if [[ $var =~ $test_regex ]] ; then
matched=0
break
fi
done
return "$matched"
}
var='aaIsAMatch'
if check_func; then
echo "A match was found"
fi
该函数已对匹配列表和变量名称进行了硬编码。
给出数组变量中的正则表达式列表以及要测试第一个参数的值:
check_func() {
local matched; matched=1
for t in "${test_regex[@]}"; do
[[ $1 =~ $t ]] && { matched=0; break; }
done
return "$matched"
}
test_regex=('^aa' '^abc' '^3@3' '>')
if check_func 'aaIsAMatch'; then
echo "A match was found"
fi
该函数可以进一步改进以使用变量的名称(而不是值)作为第一个参数。
POSIX
由于 posix shell 中没有正则表达式,并且唯一的测试方法是 case 语句,因此我们必须使用 case 语句。遗憾的是,对于较旧的 shell([没有可用的扩展 glob][1]),我们必须循环进行所有测试。并且,glob 必须是:
'aa*' 'abc*' '3@3*' '*>*'
针对多个 glob 测试多个输入字符串的脚本示例:
check_func() { :
matched=1
value=$1; shift
for t in "$@"; do
case $value in $t) matched=0; #break;; esac
echo "matched $value with $t"
;;
esac
done
return "$matched"
}
for var in abdg wabcde aadef abcde 3@3hello hmm3@3hell 'we>we' 'a>dfff' 'dfd>' 'a> de' 'a*> fg'; do
if check_func "$var" 'aa*' 'abc*' '3@3*' '*>*'; then
echo "========A match was found for \"$var\""
fi
done
该函数的更简单版本完全符合您的要求:
check_func() { :
matched=1
value=$1; shift
for t in "$@"; do
case $value in $t) matched=0; break;; esac
done
return "$matched"
}
答案3
该语句的作用如下case
:将第二个参数传递给函数 ( $2
)。如果它与模式匹配"$1"*
,即函数的第一个参数后跟任何内容,则执行true
并结束该case
语句。true
不执行任何操作并返回状态 0。否则,如果匹配*
,即任何内容,则执行false
并结束该case
语句。false
不执行任何操作并返回状态 1。因此,case
如果第二个参数以第一个参数开头,则该语句的状态为 0,否则为 1。由于这是函数中的最后一个(也是唯一一个)语句,因此如果第二个参数以第一个参数开头,则函数返回 0,否则返回 1。
条件语句(例如if
shell 中的条件语句)如果返回 0,则认为语句为真,否则认为语句为假。因此,如果 的值以以下开头,则打印,否则if beginswith "$var" "string"; then echo yes; else echo no; fi
打印。yes
var
string
no
有几种替代方法可以编写此函数。例如,作者可以使用return 0
orreturn 1
代替true
and false
,因为它们是函数中的最后一个语句。函数的编写方式使得可以直接使用其函数体,而无需将其包装在函数中,只需将对函数参数 ($1
和$2
) 的引用更改为您想要使用的任何字符串即可。
要允许多个前缀,请在循环中迭代它们。一旦找到匹配的前缀,就会从函数返回,状态为 true (0)。如果没有任何前缀匹配,则返回错误状态(通常为 1)。
# begins_with STRING PREFIX1 PREFIX2...
# Test if STRING starts with any of PREFIX1, PREFIX2, ...
begins_with () {
string=$1
shift
for prefix in "$@"; do
case "$string" in
"$prefix"*) return 0;;
esac
done
return 1
}
if begins_with "$var" 'aa' 'abc' '3@3'; then
echo "The value starts with one of the permitted prefixes"
fi
要测试后缀,请使用模式*"$suffix"
而不是"$prefix"*
.要测试子字符串,请使用*"$substring"*
.请注意,此处必须使用双引号,否则变量将被解释为模式。例如:
suffix='?'
case "$var" in
*"$suffix") echo "The value of var ends with a question mark";;
esac
case "$var" in
*$suffix) echo "The value of var is not empty";;
esac
答案4
根据问题的澄清进行修改: 这不太优雅(也不太灵活),但比其他答案更紧凑,
check_func() {
case "$1" in
( aa* | abc* | 3@3* | *">"*)
return 0
esac
return 1
}
aardvark
对于、abcdef
和[email protected]
,这返回 true 12>5
。当然,还有aard>vark
、abc<def>ghi
和3@3>3
。