有没有更简单的方法来在函数内本地设置 $path 数组?

kjo*_*kjo 5 scripting zsh shell-script

是否有$path比以下代码段中显示的更轻松的方法来设置数组的本地版本?

foo () {
    local holdpath
    holdpath=($path)
    local path
    path=($holdpath)
    if ( some_condition ) path=( $PREFIX $path )

    # do stuff
}
Run Code Online (Sandbox Code Playgroud)

我特别指的是与holdpath...的歌舞

如果相反我定义

foo () {
    local path=($path)
    if ( some_condition ) path=( $PREFIX $path )

    # do stuff
}
Run Code Online (Sandbox Code Playgroud)

...第一个赋值path触发bad pattern错误。当然,如果相反我定义

foo () {
    local path
    path=($path)
    if ( some_condition ) path=( $PREFIX $path )

    # do stuff
}
Run Code Online (Sandbox Code Playgroud)

...第一次赋值path没有区别(即可以省略而不改变结果);有或没有它,$path都会是空的。

编辑:

以下脚本测试了我目前得到的各种建议:

foo_0 () {
  echo ${#path}
  local PATH=$PATH
  echo ${#path}
}

foo_1 () {
  echo ${#path}
  eval "local path; path=(${(q)path})"
  echo ${#path}
}

foo_2 () {
  echo ${#path}
  eval "$(local -p path)"
  echo ${#path}
}

for i ( 0 1 2 ) {
  fn=foo_$i
  echo "# $fn"
  $fn
  echo
}
Run Code Online (Sandbox Code Playgroud)

输出是:

# foo_0
22
22

# foo_1
22
1

# foo_2
22
22
Run Code Online (Sandbox Code Playgroud)

所以输出foo_0foo_2至少与我试图实现的目标一致。foo_1上面给出的某些东西不起作用,但我摆脱(q)了分配给path,即

foo_1 () {
  echo ${#path}
  eval "local path; path=($path)"
  echo ${#path}
}
Run Code Online (Sandbox Code Playgroud)

...然后输出与foo_0和 的一致foo_2。不幸的是,即使在阅读了q几次限定符的文档之后,我还是不太明白它在原始配方中应该做什么。

另外,我不明白为什么以下命令行变体foo_0与上面的不同:

% (foo_0a () { echo ${#path}; local PATH=$PATH; echo ${#path} }; foo_0a)
22
1
Run Code Online (Sandbox Code Playgroud)

FWIW,相应的命令行的变体foo_1foo_2产生相同的结果作为其在脚本原稿:

% (foo_1a () { echo ${#path}; eval "local path; path=(${(q)path})"; echo ${#path} }; foo_1a)
22
1
% (foo_2a () { echo ${#path}; eval "$(local -p path)"; echo ${#path}; }; foo_2a)
22
22
Run Code Online (Sandbox Code Playgroud)

此外,在上述所有情况下,echo ${#path}产生1而不是22原因是局部$path变量包含单个字符串中的所有单独路径,用空格分隔。

ric*_*ici 5

使用标量PATH形式而不是数组path。使这些本地有效地使它们都本地化,因此:

foo() {
  local PATH=$PATH
  if ( some_condition ) path=( $PREFIX $path )

  # do stuff
}
Run Code Online (Sandbox Code Playgroud)

(请注意,如果某些路径组件具有嵌入的:. ,则这将不起作用。)

不幸的是,不可能在一个语句中初始化本地数组参数,从而无法使用其原始值初始化本地数组参数。


Sté*_*las 3

对于绑定数组,您可以使用rici 的答案,在一般情况下,您可以这样做:

foo() {
  eval "local array; array=(${(q)array[@]})"
  ...
}
Run Code Online (Sandbox Code Playgroud)

(q)是引用数组的元素。例如,对于$PATHlike的值/foo bar:/x$y"${(q)path[@]}"将扩展为/foo\ bar /x\$y。我们需要转义这些空格和美元字符,因为该字符串被传递给eval.

你还可以这样做:

foo() {
  eval "$(local -p array)"
  ...
}
Run Code Online (Sandbox Code Playgroud)

它适用于任何类型的变量,但这会产生一个额外的过程。