删除前导空格在 Bash 中不起作用
Deleting leading spaces is not working in Bash
我在 Bash 中有一个字符串,它可能以也可能不以任意数量的前导 space 开头,例如
" foo bar baz"
" foo bar baz"
"foo bar baz"
我想从字符串中删除“foo”的第一个实例,以及任何前导 spaces(可能没有)。
根据 的建议,我尝试了以下方法:
str=" foo bar baz"
regex="[[:space:]]*foo"
echo "${str#$regex}"
echo "${str#[[:space:]]*foo}"
如果str有一个或多个前导space,那么它将return我想要的结果,即_bar baz
(下划线 = 前导 space)。如果字符串有 没有 前导 space,它不会做任何事情并且会 return foo bar baz
。 'echoes' return 这里的结果相同。
我的理解是,在[[:space:]]
之后使用*
应该匹配0个或多个[[:space:]实例,不是一个或多个。我在这里遗漏了什么或做错了什么?
编辑
@Raman - 我尝试了以下方法,但它们也不起作用:
echo "${str#[[:space:]]?foo}"
echo "${str#?([[:space:]])foo}"
echo "${str#*([[:space:]])foo}"
无论是否有尾随space,这三种解决方案都不会删除'foo'。唯一可行的解决方案是我发布的带有星号的解决方案 - 当有尾随 space 时它将删除 'foo',但没有尾随时则不会。
最好的办法是使用参数扩展(带有扩展的 glob),如下所示:
# 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"}"
会起作用。如果 pattern
的扩展包含 glob 字符,则必须引用它。例如当 pattern="foo[1]"
.
My understanding is that using * after [[:space:]] should match zero or more instances of [[:space:]], not one or more
错了。
What am I missing
那个glob is not regex。在 regex 中,*
匹配零个或多个前面的字符或组。在 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]
请注意,这会让您在任何更复杂的情况下陷入各种混乱。
如果您想在值之间保留多个连续的 space 或制表符而不只是引号等,它会中断
$: str=' foo bar'$'\t''baz';
$: echo "[$str]"
[ foo bar baz]
$: new=$( echo $str )
$: echo "[$new]"
[foo bar baz]
它也可能导致其他类型的破坏,但在适当的时候了解情况下的技巧是很好的。
我在 Bash 中有一个字符串,它可能以也可能不以任意数量的前导 space 开头,例如
" foo bar baz"
" foo bar baz"
"foo bar baz"
我想从字符串中删除“foo”的第一个实例,以及任何前导 spaces(可能没有)。
根据
str=" foo bar baz"
regex="[[:space:]]*foo"
echo "${str#$regex}"
echo "${str#[[:space:]]*foo}"
如果str有一个或多个前导space,那么它将return我想要的结果,即_bar baz
(下划线 = 前导 space)。如果字符串有 没有 前导 space,它不会做任何事情并且会 return foo bar baz
。 'echoes' return 这里的结果相同。
我的理解是,在[[:space:]]
之后使用*
应该匹配0个或多个[[:space:]实例,不是一个或多个。我在这里遗漏了什么或做错了什么?
编辑
@Raman - 我尝试了以下方法,但它们也不起作用:
echo "${str#[[:space:]]?foo}"
echo "${str#?([[:space:]])foo}"
echo "${str#*([[:space:]])foo}"
无论是否有尾随space,这三种解决方案都不会删除'foo'。唯一可行的解决方案是我发布的带有星号的解决方案 - 当有尾随 space 时它将删除 'foo',但没有尾随时则不会。
最好的办法是使用参数扩展(带有扩展的 glob),如下所示:
# 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"}"
会起作用。如果 pattern
的扩展包含 glob 字符,则必须引用它。例如当 pattern="foo[1]"
.
My understanding is that using * after [[:space:]] should match zero or more instances of [[:space:]], not one or more
错了。
What am I missing
那个glob is not regex。在 regex 中,*
匹配零个或多个前面的字符或组。在 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]
请注意,这会让您在任何更复杂的情况下陷入各种混乱。 如果您想在值之间保留多个连续的 space 或制表符而不只是引号等,它会中断
$: str=' foo bar'$'\t''baz';
$: echo "[$str]"
[ foo bar baz]
$: new=$( echo $str )
$: echo "[$new]"
[foo bar baz]
它也可能导致其他类型的破坏,但在适当的时候了解情况下的技巧是很好的。