String 删除前导空格在Bash中不起作用
我在Bash中有一个字符串,它可能以任何数量的前导空格开头,也可能不以任何数量的前导空格开头,例如String 删除前导空格在Bash中不起作用,string,bash,removing-whitespace,parameter-expansion,String,Bash,Removing Whitespace,Parameter Expansion,我在Bash中有一个字符串,它可能以任何数量的前导空格开头,也可能不以任何数量的前导空格开头,例如 " foo bar baz" " foo bar baz" "foo bar baz" 我想从字符串中删除“foo”的第一个实例,以及任何前导空格(可能没有) 根据来自的建议,我尝试了以下方法: str=" foo bar baz" regex="[[:space:]]*foo" echo &q
" foo bar baz"
" foo bar baz"
"foo bar baz"
我想从字符串中删除“foo”的第一个实例,以及任何前导空格(可能没有)
根据来自的建议,我尝试了以下方法:
str=" foo bar baz"
regex="[[:space:]]*foo"
echo "${str#$regex}"
echo "${str#[[:space:]]*foo}"
如果str有一个或多个前导空格,那么它将返回我想要的结果,即\u bar baz
(下划线=前导空格)。如果字符串没有前导空格,它将不会执行任何操作并返回foobarbaz
。这两个“回声”在这里返回相同的结果
我的理解是,在[:space:]
之后使用*
应该匹配[[:space:]]的零个或多个实例,而不是一个或多个。我在这里错过了什么或做错了什么
编辑
@拉曼-我尝试了以下方法,但它们也不起作用:
echo "${str#[[:space:]]?foo}"
echo "${str#?([[:space:]])foo}"
echo "${str#*([[:space:]])foo}"
无论是否有尾随空格,这三种解决方案都不会删除“foo”。唯一有效的解决方案是我发布的带有星号的解决方案——当有尾随空格时,它将删除“foo”,但当没有尾随空格时,它不会删除。“最好的做法是使用参数展开(使用扩展全局变量),如下所示:
# Make sure extglob is enabled
shopt -s extglob
str=" foo bar baz"
echo "${str##*([[:space:]])}"
这使用了扩展的glob*([[:space:]])
,以及参数扩展(贪婪匹配)
编辑。由于您的模式具有后缀foo
,因此不需要使用贪婪匹配:
echo "${str#*([[:space:]])foo}"
够了
注意。您也可以将foo
放入变量中,但要小心,您必须引用它:
pattern=foo
echo "${str#*([[:space:]])"$pattern"}"
会有用的。如果模式
的扩展包含glob字符,则必须引用它。例如,当pattern=“foo[1]”
时
我的理解是,在[[:space:]之后使用*应该匹配[[:space:]的零个或多个实例,而不是一个或多个
那是错误的
我错过了什么
事实并非如此。在正则表达式中,*
匹配零个或多个前面的字符或组。在glob*
中,匹配任何内容。这与文件名扩展相同,请考虑ls[[:space:]*foo
您可以使用扩展bash glob并执行以下操作:
shopt -s extglob
str=' foo bar baz'
echo "${str#*([[:space:]])foo}"
要做任何更复杂的事情,实际上使用正则表达式
str=' foo bar baz';
[[ $str =~ ^[[:space:]]*foo(.*) ]];
echo "${BASH_REMATCH[1]}"
如果您想要的是真正的正则表达式匹配,则应使用真正的正则表达式匹配:
$: [[ "$str" =~ [[:space:]]*(.*) ]]
$: echo "[${BASH_REMATCH[1]}]"
[foo bar baz]
一个更普通的方法是跳过引用
$: echo "[$str]"
[ foo bar baz]
$: new=$( echo $str )
$: echo "[$new]"
[foo bar baz]
请注意,在任何更复杂的情况下,这会让你面临各种各样的麻烦。
如果您想在值之间保留多个连续的空格,或者只保留一个选项卡而不只是一个引号等,则会中断
$: str=' foo bar'$'\t''baz';
$: echo "[$str]"
[ foo bar baz]
$: new=$( echo $str )
$: echo "[$new]"
[foo bar baz]
它也可能造成其他类型的破坏,但在适当的时候知道这种情况的诀窍是很好的。@RamanSailopal说?
匹配零次或一次,而*
匹配零次或多次。无论如何我都试过了,但没用-会更新问题。而且也没用:
启用extglob…只是${str#foo}
有什么问题?@oguzismail在str=oguzfoo
的情况下,我想op不需要匹配。@Lou:只是为了确保这不是XY问题:你想在空格处拆分字符串吗?如果是这样的话,您应该改为使用:read-ra-ary-d'#
也有效。啊,我想你也想删除foo
后面的空格。谢谢,这很有效!出于兴趣,为什么要用最长的匹配而不是最短的匹配?@Lou:否则只会删除第一个空格。但是现在我意识到你的模式中也有foo
,所以echo“${str#*([[:space:]])foo}”
就足够了。我已经编辑了答案(还添加了关于将模式放入变量的备注)。@Lou:1。您不需要在re
中引用标记foo
:这就足够了:re=“*([[:space:])foo*([[:space:])”
。2.不得引用该模式!实际上,这里的引号是为了防止将模式解释为模式!因此:echo“${str#$re}”
(不带引号的$re
)是正确的。@Lou:不完全:)只有当您不想将模式变量解释为模式时,才应该在参数展开中引用它。这里有一个非常简单的例子,你可以试试:str=“foo-bar”;pattern=“*”
。(事实上,我们在这里使用引号是不相关的)。没有引号:echo“${str#$pattern}”
您将获得oo条
,因为str
与模式f*
匹配。但是有了引号:echo“${str#“$pattern”}”
,你会得到foobar
,因为str
与pattern
的逐字内容不匹配,这是f*
。啊,这很有道理!谢谢你解释得这么清楚:)这不是我想做的-我只想从字符串前面加上一个给定的单词来修剪前导空格,而不是从字符串中的所有单词来修剪前导空格。这就是为什么我要警告它。第一个匹配解决方案是更好的方法