问题描述
如何在不产生另一个进程的情况下从 Zsh 中的字符串末尾删除任何和所有空格?
在查看 the documentation for expansion in Zsh(即 14.3 Parameter Expansion 和 14.8.1 Glob Operators 部分)(也可通过 $ man zshexpn
查看)后,我编写了以下代码:
${${var##[:space:]##}%%[:space:]##}
但 Zsh 似乎无法识别 [:space:]
glob 运算符。根据我对文档中以下语句的理解,它应该:
在下面讨论的需要模式的扩展中,模式的形式与用于文件名生成的形式相同;请参阅文件名生成。请注意,这些模式以及任何替换的替换文本本身都会受到参数扩展、命令替换和算术扩展的影响。
这是 Zsh 中的错误还是我忽略了什么?
目前,我只是使用 ${${var## ##}%% ##}
,它至少会替换末尾的任何和所有空格字符。
我使用的是 Zsh 5.8。
解决方法
引用 zsh
Glob Operator 文档:
请注意,方括号是对包含整个字符集的方括号的补充,因此要测试单个字母数字字符,您需要 ‘[[:alnum:]]’
。
所以只使用 [:space:]
而不是 [[:space:]]
是你的问题。
旁白:
在 zsh
glob 模式中,有几种方法可以表示“匹配前一个事物的多个副本”。您使用的一种需要打开 EXTENDED_GLOB
选项,是使用 x##
,它匹配一个或多个模式 x(还有 {{ 1}},它匹配零次或多次出现的模式 x)。另一个需要 x#
选项才能工作的是 KSH_GLOB
,它也匹配一个或多个 +(x)
(并且 x
匹配 0 个或多个。)这种样式具有使用 *(x)
和 ksh
(后者需要启用 bash
选项)的优势,因此来自另一个 shell 的人可能更熟悉。
所以:
extglob
根据需要删除所有前导和尾随空格字符。
另请注意,这种扩展嵌套是特定于 $ foo=$(printf " \t bar baz \t ") # Spaces and tabs before and after
$ printf ">%s<\n" "$foo"
> bar baz <
$ printf ">%s<\n" "${${foo##[[:space:]]##}%%[[:space:]]##}"
>bar baz<
$ setopt KSH_GLOB
$ printf ">%s<\n" "${${foo##+([[:space:]])}%%+([[:space:]])}"
>bar baz<
的。它不会在其他 shell 中工作,其中两次删除将需要多个步骤。
你真的很亲近。
- 您需要稍微修改一下您的 POSIX Basic Regular Expression 字符类语法
- 您可以使用
(MS)
(匹配子字符串)parameter expansion flags 来简化表达式。
${(MS)var##[[:graph:]]*[[:graph:]]}
解决方案
在下面的示例中,我们将去除前导/尾随空格的参数具有标识符 var
。根据需要在您自己的代码中替换它。
typeset var=$'\n\t abc def \n\t'
打印去除任何前导/尾随空格的参数:
print -n -- ${(MS)var##[[:graph:]]*[[:graph:]]}
输出:abc def