更改Bash函数内的全局位置参数

Cal*_*lin 6 bash shell sh

有没有办法从函数中设置bash脚本的位置参数?

在全局范围内,可以使用set -- <arguments>更改位置参数,但它在函数内部不起作用,因为它更改了函数的位置参数.

快速说明:

# file name: script.sh
# called as: ./script.sh -opt1 -opt2 arg1 arg2

function change_args() {
    set -- "a" "c" # this doesn't change the global args
}

echo "original args: $@" # original args: -opt1 -opt2 arg1 arg2
change_args
echo "changed args: $@" # changed args: -opt1 -opt2 arg1 arg2
# desired outcome:        changed args: a c
Run Code Online (Sandbox Code Playgroud)

Cir*_*sta 5

如前所述,答案是否定的,但如果有人需要这个,可以选择设置外部数组(_ARRAY),从函数内部修改它,然后set -- ${_ARRAY[@]}在事后使用。例如:

#!/bin/bash

_ARGS=()

shift_globally () {
  shift
  _ARGS=$@
}

echo "before: " "$@"
shift_globally "$@"
set -- "${_ARGS[@]}"
echo "after: " "$@"
Run Code Online (Sandbox Code Playgroud)

如果你测试一下:

./test.sh a b c d
> before:  a b c d
> after:  b c d
Run Code Online (Sandbox Code Playgroud)

从技术上讲,这不是您所要求的,但它是一种解决方法,可能会帮助需要类似行为的人。


koj*_*iro 1

并不真地。函数实际上有自己的作用域。默认情况下,在函数中分配的参数是全局的,但如果您显式声明它,则它具有本地范围:

foo() {
    x=3 # global
    declare y # local
    ...
}
Run Code Online (Sandbox Code Playgroud)

位置参数始终是函数的本地参数,因此您对它们进行的任何操作都只会在函数范围内生效。

从技术上讲,您始终可以使用递归来解决这个问题。如果您可以放心地再次调用原始脚本,则可以通过这种方式重新排序参数。例如

declare -i depth

outer() {
    if (( depth++ < 1 )); then
        outer "${@:4:$#}" "${@:1:3}"
        return
    fi
    main "$@"
}

main() {
    printf '%s\n' "$@"
}

outer "$@"
Run Code Online (Sandbox Code Playgroud)

对于我不理解的问题,这似乎是一个容易出错且令人困惑的解决方案,但它本质上是有效的。