从函数内部更新调用方的参数数组

时间:2019-03-14 00:04:19

标签: bash function command-line-arguments

在Bash中,我可以这样设置$@

set -- a b c

然后,我可以检查$@的内容:

printf '%s\n' "$@"

它将显示:

a
b
c

但是,如果我在函数中这样做:

f() {
    set d e f
}

set a b c
f
printf '%s\n' "$@"

我仍然得到

a
b
c

不是

d
e
f

如何使我的函数更新调用方的$@?我尝试使用BASH_ARGV,但没有用。

我正在尝试编写一个处理命令行参数并从中删除某些项(同时设置变量)的函数,以便调用者无需理会它们。例如,如果我使用--debug调用它们,而无需编写代码来处理每个脚本中的代码并将该逻辑放在一个通用的“源代码”函数中,则我希望所有脚本都打开它们的调试日志记录。 / p>

注意:我不想派生一个subshel​​l。

3 个答案:

答案 0 :(得分:0)

您不能更改参数的值,因为它们是通过引用传递的 在bash函数中。

最好的办法是传递要处理的参数,然后返回 尚未处理的。

以下内容:

process_arguments() {
    # process the arguments
    echo "original arguments : $@"
    local new_arguments=(a c)

    echo ${new_arguments[@])
}

new_arguments=$(process_arguments a b c)
set -- $new_arguments

如果您不想麻烦“ subshel​​l”,则可以使用全局变量:

arguments=""

process_arguments() {
    # process the arguments
    echo "original arguments : $@"
    local new_arguments=(a c)
    arguments="${new_arguments[@]}"
}

process_arguments a b c # no subshell
set -- $arguments        

按照@ruakh的建议,您还可以使用arguments作为数组,如下所示:

arguments=()

process_arguments() {
    # process the arguments
    echo "original arguments : $@"
    local new_arguments=(a c)
    arguments=( "${new_arguments[@]}" )
}

process_arguments a b c # no subshell
set -- "${arguments[@]}"

答案 1 :(得分:0)

这是 scope的问题:每个函数都有自己的参数数组,与脚本无关:

$ cat test.bash 
#!/usr/bin/env bash
f() {
    printf '%s\n' "Function arguments:" "$@"
}
printf '%s\n' "Script arguments:" "$@"
f 'a b' 'c d'
$ chmod u+x test.bash
$ ./test.bash 'foo bar' baz
Script arguments:
foo bar
baz
Function arguments:
a b
c d

因此,当您set参数数组时,该参数数组仅在当前范围内适用。如果要更改脚本参数数组,则需要set在任何函数的外部中。像set -- $(f)这样的骇客一般无法使用,因为它无法处理引数中的空白。

一个通用的解决方案变得更加难看:您需要在函数中printf '%s\0' "$parameter",在脚本中while IFS= read -r -d'' -u9,将返回的值放入数组,然后set -- "${arguments[@]}"。 / p>

我希望这可以通过其他方式可靠地完成,但这就是我所得到的。

答案 2 :(得分:0)

vfalcao's方法是很好的方法,尽管该答案中的代码无法正确处理空格。

以下是基于相同想法的代码,可以很好地处理空白:

wrapper() {
  # filter args
  args=()
  for arg; do
    if [[ $arg = arg1 ]]; then
      # process arg1
    elif [[ $arg = arg2 ]]; then
      # process arg2
    elif ...
      # process other args
    else
      args+=("$arg")
    fi
  
    # call function with filtered args
    wrapped_function "$args[@]"
  done
}

wrapper "$@"

此处为示例实现:base-wrapper