从 Zsh 旁白:

问题描述

如何在不产生另一个进程的情况下从 Zsh 中的字符串末尾删除任何和所有空格?

在查看 the documentation for expansion in Zsh(即 14.3 Parameter Expansion14.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 中工作,其中两次删除将需要多个步骤。

,

你真的很亲近。

  1. 您需要稍微修改一下您的 POSIX Basic Regular Expression 字符类语法
  2. 您可以使用 (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