我的变量中包含一个字符串,我想根据相对于另一个子字符串的位置提取子字符串。除非字符串作为参数发送到函数,否则我的解决方案似乎有效。我正在使用 bash shell。
#!/usr/bin/bash
var0="-a check one two three"
var1="check"
function getsubstr() {
echo ${*#*"${2}"}
}
# this prints 'one two three' which is what I want
echo ${var0#*"${var1}"}
# this prints '-a one two three', not what I want.
getsubstr $var0
请注意,当我放入echo $*
函数时,它会打印与(-> '-a check one 二三')getsubstr
相同的字符串,而当我放入函数时,它会打印与(-> 'check')相同的字符串。所以,在我看来,我要求在两种情况下打印相同的子字符串。$var0
echo $2
getsubstr
$var1
另一个难题是,如果不是echo ${*#*"${2}"}
在getsubstr
我使用的函数中echo ${*%"${2}"*}
,我得到完全相同的结果。
任何有助于理解这种行为的帮助将不胜感激。
顺便说一句,我意识到 函数${*:3}
内部getsubstr
可以返回我想要的子字符串,但我试图理解#*<regexp>
和%<regextp>*
行为。
答案1
您getsubstr $var0
正在向函数传递 5 个参数。
另外,$* 和 $@ 测试每个人1 美元 2 美元等..arg 反对#图案。
关于正则表达式bash
:我在最后添加了一些示例,顺便说一句,“*”只是一个特殊正则表达式字符当它在正则表达式上下文中使用时,即。使用时 =~。在第一次使用 * in 时${*
,星号的特殊用途是(伪)名称一个 var 扩展为所有变量的串联: $1 $2 $...等...
第二次使用星号,在#*"${2}"
, 中意味着“$2” 前面没有任何内容,将分别/单独地与每个传递的 $1 等参数进行匹配。
以下脚本可能对 $@ 和 $* 有帮助(例如)...
#!/bin/bash
#
getsubstr() {
echo -n " ${#@} args";
[[ "$1$2$3$4$5$6" == *\ * ]] && echo " (with embedded spaces)" || echo " (no spaces)"
echo ' "${*}" '\|"${*}"\|
echo ' ${*} '\|${*}\|
echo ' "${@}" '\|"${@}"\|
echo ' ${@} '\|${@}\|
echo ' "${*#*"${2}}" '\|"${*#*"${2}"}"\|
echo ' ${*#*"${2}} '\|${*#*"${2}"}\|
echo ' "${@#*"${2}}" '\|"${@#*"${2}"}"\|
echo ' ${@#*"${2}} '\|${@#*"${2}"}\|
echo ' ${*#B} '\|${*#B}\|
echo ' "${*#B}" '\|"${*#B}"\|
echo ' ${@#B} '\|${@#B}\|
echo ' "${@#B}" '\|"${@#B}"\|
}
var0="a B c "
echo
echo -n "Passing "; getsubstr "$var0" ; echo
echo -n "Passing "; getsubstr $var0 ; echo
echo -n "Passing "; getsubstr "$var0" "$var0" ; echo
echo -n "Passing "; getsubstr $var0 $var0 ; echo
echo
exit
###################################################################
正则表达式在bash
# Regex checks: "=~" uses extended regular expression
#+ Parenthesized subexpressions within the regular expression are saved
#+ in the array variable BASH_REMATCH
#+ $BASH_REMATCH / ${BASH_REMATCH[0]} is the string matching the entire regular expression.
#+ ${BASH_REMATCH[n]} is the sub string matching the nth parenthesized subexpression
[[ "abcdef" =~ (.)(.)(.) ]] && echo "# $BASH_REMATCH"
# abc
[[ "abcdef" =~ (.)(.)(.) ]] && echo "# ${BASH_REMATCH[0]}"
# abc
[[ "abcdef" =~ (.)(.)(.) ]] && echo "# ${BASH_REMATCH[2]}"
# b
[[ "abcdef" =~ (.)(.)(.) ]] && echo "# ${BASH_REMATCH[@]}"
# abc a b c
答案2
更新并附有解释
您看到这种类型行为的原因是因为$*
或什至$@
扩展到所有位置参数:$1
等$2
。当您尝试执行参数扩展(PE) 在这两个特殊变量之一上,您将 PE 应用于每个位置参数,并且不是单个字符串。
摘自man bash
${参数#word}
删除匹配的前缀模式。该单词被扩展以产生一个模式,就像路径名扩展一样。如果模式与参数值的开头匹配,则扩展的结果是参数的扩展值,并#'' case) or the longest matching pattern (the
删除了最短匹配模式(##''情况)。 如果参数是@或*,则依次对每个位置参数应用模式删除操作,并且扩展是结果列表。
本质上你正在做的是这样的:
getsubstr() {
tmp=$2
for arg; do
printf "%s " ${1#*$tmp}
shift
done
}
以下函数通过设置$*
临时变量来工作$tmp
,因为您现在将 PE 应用于普通变量一次。
getsubstr() {
tmp=$*
echo ${tmp#*$2}
}
聚苯乙烯
不要使用它function
,因为它不是 POSIX,而且如果您已经()
在函数名称之后使用它,实际上完全没有必要。
聚苯硫醚
这实际上与常用表达反而球形表达式。更正式地说,这些被称为参数扩展