从 zsh 中的参数字符串中删除一些参数

Remove some arguments from argument string in zsh

我正在尝试使用 zsh parameter expansion 删除部分参数字符串(请不要使用 sed 等外部工具)。这是为了:

RUBYOPT 环境变量包含在使用 ruby 解释器时应用的参数,就像它们与 ruby 命令一起给出一样。一个参数控制警告的详细程度,可能的设置例如 -W0-W:no-deprecated。我的目标是从 RUBYOPT 中删除所有 -W...,比如:

我目前的做法是将字符串拆分为一个数组,然后对数组的每个成员进行替换。这适用于两行代码,但我无法使其适用于单行代码:

% RUBYOPT="-W:no-deprecated -X -W1"

% parts=(${(@s: :)RUBYOPT})
% echo ${parts/-W*}
-X

% echo ${(${(@s: :)RUBYOPT})/-W*}
zsh: error in flags

我在这里做错了什么......或者有不同的,更优雅的方法来实现这个?

感谢您的提示!

${(...引入参数扩展标志(例如:${(s: :)...})。

它无法将 ${(${(@s: :... 作为参数扩展处理,尤其是作为 (${(@s... 部分的参数扩展标志,因此 zsh 会产生错误 "zsh: error in flags".

    % RUBYOPT="-W:no-deprecated -X -W1"
    % print -- ${${(s: :)RUBYOPT}/-W*}
    # -X

可以拯救。


根据 rowboat 的评论更新:它可能不适合某些标志,例如 -abc-Whoops-foo-Whoo 等:

    % RUBYOPT="-W:no-deprecated -X -W1 -foo-Whoo"
    % parts=(${(s: :)RUBYOPT})
    % print -- ${parts/-W*}
    # -X -foo
    # Note: -foo would be unexpected
    % print -- ${${(s: :)RUBYOPT}/-W*}
    # -X -foo
    # Note: -foo would be unexpected

s globbing 标志(连同 shell 选项 EXTENDED_GLOB)可以挽救:

    % RUBYOPT="-W:no-deprecated -X -W1 -foo-Whoo"
    % parts=(${(s: :)RUBYOPT})
    % setopt extendedglob
    # To use `(#s)` flag which is like regex's `^`
    % print -- ${parts/(#s)-W*}
    # -X -foo-Whoo
    % print -- ${${(s: :)RUBYOPT}/(#s)-W*}
    # -X -foo-Whoo

Globbing Flags

There are various flags which affect any text to their right up to the end of the enclosing group or to the end of the pattern; they require the EXTENDED_GLOB option. All take the form (#X) where X may have one of the following forms:
...
s, e

Unlike the other flags, these have only a local effect, and each must appear on its own: (#s) and (#e) are the only valid forms. The (#s) flag succeeds only at the start of the test string, and the (#e) flag succeeds only at the end of the test string; they correspond to ^ and $ in standard regular ex‐ pressions.
...
--- zshexpn(1), Expansion, Globbing Flags

或下面描述的 ${name#:pattern} 语法也可以拯救。

根据 rowboat 的评论结束更新


可以选择使用 typeset -T 功能通过数组运算符操作标量值。

    RUBYOPT="-W:no-deprecated -X -W1"

    typeset -xT RUBYOPT rubyopt ' '
    rubyopt=(${rubyopt:#-W*})

    print -l -- "$RUBYOPT"
    # -X

typeset
...
-T [ SCALAR[=VALUE] ARRAY[=(VALUE ...)] [ SEP ] ]
...
the -T option requires zero, two, or three arguments to be present. With no arguments, the list of parameters created in this fashion is shown. With two or three arguments, the first two are the name of a scalar and of an array parameter (in that order) that will be tied together in the manner of $PATH and $path. The optional third argument is a single-character separator which will be used to join the elements of the array to form the scalar; if absent, a colon is used, as with $PATH. Only the first character of the separator is significant; any remaining characters are ignored. Multibyte characters are not yet supported. ...
Both the scalar and the array may be manipulated as normal. If one is unset, the other will automatically be unset too. ...

--- zshbuiltin(1), Shell Bultin Commands, typeset

rubyopt=(${rubyopt:#-W*})过滤数组元素

${name:#pattern}

If the pattern matches the value of name, then substitute the empty string; otherwise, just substitute the value of name. If name is an array the matching array elements are removed (use the (M) flag to remove the non-matched elements).

--- zshexpn(1), Parameter Expansion , ${name:#pattern}


注意:可以从标志中省略“@”,因为在这种情况下不需要空值。

    RUBYOPT="-W:no-deprecated -X -W1"
    parts=(${(s: :)RUBYOPT})
    print -- ${parts/-W*}
    # -X
    print -- ${${(s: :)RUBYOPT}/-W*}
    # -X

Parameter Expansion Flags
...
@
In double quotes, array elements are put into separate words. E.g., "${(@)foo}" is equivalent to "${foo[@]}" and "${(@)foo[1,2]}" is the same as "$foo[1]" "$foo[2]". This is distinct from field splitting by the f, s or z flags, which still applies within each array element.

--- zshexpn(1), Parameter Expansion Flags, @

如果我们不能省略空值,${name:#pattern}语法可以挽救。

    RUBYOPT="-W:no-deprecated  -X -W1"
    parts=("${(@s: :)RUBYOPT}")
    # parts=("-W:no-deprecated" ""  "-X" "-W1")
    # Note the empty value are retained
    print -rC1 -- "${(@qqq)parts:#-W*}"
    # ""
    # "-X"
    print -rC1 -- "${(@qqq)${(@s: :)RUBYOPT}:#-W*}"
    # ""
    # "-X"