如何引用 $@ 而不在 bash 函数中传递它?

Til*_*ill 6 shell bash shell-script

我想知道如何$@从另一个函数或另一个脚本文件引用 ,而不需要像getopts所做的那样传递它。非常感谢!

# 上一个问题: bash getopts 如何知道调用有哪些参数

A() {
  B 
} 

B() {

  # how to reference the $@ of A here ?
  # which will be 1 2 3 4


}

A 1 2 3 4
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 14

如果不以某种方式A提供其位置参数,您就无法做到这一点。B可以通过传递它们:

A() {
  B "$@"
}
B() {
  [ "$#" -eq 0 ] || printf '<%s>\n' "$@"
}
Run Code Online (Sandbox Code Playgroud)

或者将它们存储在数组中:

A() {
  A_args=( "$@" )
  B
}
B() {
  [ "${#A_args[@]}" -eq 0 ] || printf '<%s>\n' "${A_args[@]}"
}
Run Code Online (Sandbox Code Playgroud)

由于 bash 与 ash/ksh88/zsh(但与 ksh93 或 zsh 的private变量不同)对其局部变量进行动态作用域,您甚至可以将该A_args变量设置local为,A并且它仍然可以在调用的函数中使用A

bash允许您访问其父作用域的变量,即使它们被当前作用域中的局部变量隐藏unset,通过利用其内置函数的当前错误(在某些情况下不会取消设置,但会显示父作用域中的变量),但是您无法以这种方式从父作用域访问位置参数,因为在 bash 中(与zsh//相反),位置参数无法映射到数组变量rcfish因为 bash 数组设计是按照 Korn shell 的设计而设计的,而数组则不然真的是数组。

如果您希望某些代码能够访问或修改(通过shiftset)函数的位置参数或本地选项,或者return从函数中访问或修改,则需要该代码在该函数的范围内运行,因此不能在单独的函数中。

您可以使用别名(它们是 C 预处理器宏的 shell 等效项,但它们不能接受参数)或不过eval

但请注意:

  • 在 bash shell 中以及不在 POSIX 模式下时,默认情况下会禁用别名扩展,因此您需要shopt -s expand_aliases.
  • 别名必须在读取函数代码之前存在,并且在函数代码内部展开。

所以你可以这样做:

[ -z "$BASH_VERSION" ] || shopt -s expand_aliases # work around for bash
alias B='{
  [ "$#" -eq 0 || printf "<%s>\n" "$@"
  shift
}'
A() {
  echo "$#"
  B
  echo "$#"
}
A a b c
Run Code Online (Sandbox Code Playgroud)

或者:

B='
  [ "$#" -eq 0 || printf "<%s>\n" "$@"
  shift
'
A() {
  echo "$#"
  eval "$B"
  echo "$#"
}
A a b c
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 5

实际上,在 bash 中,当启用该选项(通常用于调试器)时,调用堆栈中所有函数的位置参数列表将在包含参数数量的特殊数组extdebug中可用$BASH_ARGV(尽管顺序相反)$BASH_ARGC在每个级别。

但请注意:

  • 这些是只读的(好吧,尝试改变它们的值没有效果)
  • extdebug 必须从一开始就设置(在调用第一个函数之前),但不能在 bash 命令行 ( bash -O extdebug) 上设置,因为它会调用调试器。
  • 检查手册以了解启用该选项的其他影响。
shopt -s extdebug
shopt -u xpg_echo
A() {
  B x y
}

reverse_helper() { caller_args=( "${BASH_ARGV[@]:0:BASH_ARGC}" ); }

B() {
  local -a caller_args
  local IFS=,
  reverse_helper "${BASH_ARGV[@]:BASH_ARGC[0]:BASH_ARGC[1]}"
  echo "my args: $*"
  echo "my caller args: ${caller_args[*]}"
}

A a b c
Run Code Online (Sandbox Code Playgroud)

这使:

shopt -s extdebug
shopt -u xpg_echo
A() {
  B x y
}

reverse_helper() { caller_args=( "${BASH_ARGV[@]:0:BASH_ARGC}" ); }

B() {
  local -a caller_args
  local IFS=,
  reverse_helper "${BASH_ARGV[@]:BASH_ARGC[0]:BASH_ARGC[1]}"
  echo "my args: $*"
  echo "my caller args: ${caller_args[*]}"
}

A a b c
Run Code Online (Sandbox Code Playgroud)