在变量中存储Bash函数参数

时间:2018-02-05 16:05:50

标签: bash function variables parameter-passing

我想定义并获取作为参数传递给函数的所有必需变量:

function explain_vars() {
  echo "Explaining vars '$@':" >&2
  for _var in "$@"; do
    printf "  $_var: '${!_var}'\n" >&2
  done
  printf "\n" >&2
}

function read_params() (
  ## Define local variables
  _vars=(v1 v2 v3) 
  local ${_vars[@]}

  ## Read variables from input:
  read ${_vars[@]} <<< "$@"
  explain_vars "${_vars[@]}"
)

read take将所有参数放在指定的变量中,默认分隔符在这里是空格。因此,如果我将不同的字符串作为第二个参数传递,read将仅存储第二个参数中的第一个字符串,并将所有其余字符串存储为以下参数:

$ read_params one "two dot one" "three" "four"
Explaining vars 'v1 v2 v3':
  v1: 'one'
  v2: 'two'
  v3: 'dot one three four'

我们可以看到,变量v2不再与给定参数同步。此外,它无法读取空字符串:

$ read_params one "" " " '' ' ' "two dot one" "three" "four"
Explaining vars 'v1 v2 v3':
  v1: 'one'
  v2: 'two'
  v3: 'dot one three four'

通过在函数内循环遍历所有参数变量$ @,可以区分变量:

function raw_params() (
  echo "Explaining row parameters:"
  for _v in "${@}"; do
    printf "  '$_v'\n"
  done
)

$ raw_params one "" " " '' ' ' "two dot one" "three" "four"
Explaining row parameters:
  'one'
  ''
  ' '
  ''
  ' '
  'two dot one'
  'three'
  'four'

对我来说,read命令提供了定义,控制和检查传递给函数的请求参数的好处和速度。但是,这仅适用于单个和非空的弦乐参数。是否可以读取变量中的所有不同参数,例如read命令,但尊重空格和空参数?或者有更好的方法吗?

3 个答案:

答案 0 :(得分:1)

我不确定您希望使用此代码完成什么,但这似乎可以解决三个输入参数的问题。也许它向你展示了前进的方向,即使它没有完全按照你的意愿行事。

read_params () (
  ## Define local variables
  _vars=(v1 v2 v3) 
  local ${_vars[@]}

  local i
  for ((i=1; i<=$#; ++i)); do
     ## Read variables from input:
     printf -v "${_vars[i-1]}" "${!i}"
  done
  explain_vars "${_vars[@]}"
)

答案 1 :(得分:1)

从原始问题看来read命令未正确理解,read是内置函数,读取一行标准输入,IFS环境变量用作字段分隔符,-d 1}}选项允许更改记录分隔符(默认为换行符),有关详细信息,请参阅bash手册中的read

使用特殊变量"$@"检索函数参数,bash语法分配数组只是

_vars=( "$@" )   # no space between variable name and = and no space between = and (

如果空格在变量名${!_var}中无效,则扩展将无法编写错误bash: ...: bad substitution,如果_var包含带空格的表达式。

由于function

()关键字无用,在函数体周围使用括号而不是大括号{ ;}会启动一个新的子shell。

答案 2 :(得分:0)

我根据tripleee的回答在脚本中重写了我的函数。除了将空值(''和“”)分配给printf之外,arrays工作正常。为此,我们需要使用'%s'格式化传递给printf -v的字符串。对于示例,我将一个参数数组传递给我的函数两次:每次将它们分配给我的常规本地参数;第二次将相同的参数传递给我的上一个本地数组变量。这是代码:

$ cat parse-local-vars.sh
#!/usr/bin/env bash
function explain_vars() {
  echo "Explaining vars '$@':" >&2
  for _var in "$@"; do
    printf "  $_var: '${!_var}'\n" >&2
  done
}

function parse_params() (
  #
  # Stores given parameters in defined local variables _vars.
  # Last variable will be treated as an array and 
  # remaining parameters will be stored therein.
  #

  ## Define local variables
  local _vars=(v1 v_empty_double_quote v_spaced_double_quote v_empty_single_quote v_spaced_single_quote v2_1 v3 v4 args) 
  local ${_vars[@]}

  ## Make sure we assign parameters to variables
  [ ${#_vars[@]} -gt 0 ] \
    || return 1

  _args_pos=$(( ${#_vars[@]}-1 ))
  _args_counter=0
  local p
  for ((p=1; p<=$#; ++p)); do
     ## Read variables from input:
     if [ $p -le $_args_pos ]; then
       #printf -v "${_vars[p-1]}" '%s' "${!p}"
       printf -v "${_vars[p-1]}" "${!p}"  
     else
       #printf -v "${_vars[_args_pos]}[$_args_counter]" '%s' "${!p}"
       printf -v "${_vars[_args_pos]}[$_args_counter]" "${!p}"  # Without the '%s' assigning empty variable to an array does not work
       _args_counter=$(( _args_counter+1 ))
     fi
  done
  explain_vars "${_vars[@]}"
  echo "exlaining array args[@]: '${args[@]}'"
  for _v in "${args[@]}"; do
    echo "   >'$_v'"
  done
)

params_to_test=(one "" "  " '' '  ' "two dot one" "three" "four")
parse_params "${params_to_test[@]}" "${params_to_test[@]}"

正如我所看到的,这里我使用printf -v而不格式化参数字符串(不使用'%s'):

$ bash parse-local-vars.sh
Explaining vars 'v1 v_empty_double_quote v_spaced_double_quote v_empty_single_quote v_spaced_single_quote v2_1 v3 v4 args':
  v1: 'one'
  v_empty_double_quote: ''
  v_spaced_double_quote: '  '
  v_empty_single_quote: ''
  v_spaced_single_quote: '  '
  v2_1: 'two dot one'
  v3: 'three'
  v4: 'four'
  args: 'one'
exlaining array args[@]: 'one       two dot one three four' (6 values)
   >'one'
   >'  '
   >'  '
   >'two dot one'
   >'three'
   >'four'

空参数“”和“'不会传递给数组(6个值)。 通过切换以下注释来允许printf的字符串格式:

printf -v "${_vars[_args_pos]}[$_args_counter]" '%s' "${!p}"
#printf -v "${_vars[_args_pos]}[$_args_counter]" "${!p}"  # Without the '%s' as,signing empty variable to an array does not work

导致此输出:

$ bash parse-local-vars.sh
Explaining vars 'v1 v_empty_double_quote v_spaced_double_quote v_empty_single_quote v_spaced_single_quote v2_1 v3 v4 args':
  v1: 'one'
  v_empty_double_quote: ''
  v_spaced_double_quote: '  '
  v_empty_single_quote: ''
  v_spaced_single_quote: '  '
  v2_1: 'two dot one'
  v3: 'three'
  v4: 'four'
  args: 'one'
exlaining array args[@]: 'one         two dot one three four' (8 values)
   >'one'
   >''
   >'  '
   >''
   >'  '
   >'two dot one'
   >'three'
   >'four'

这是预期的结果,因为空字符串被正确分配给数组(8个值)。我还没弄清楚将空字符串传递给printf -v的数组是怎么回事,但是使用带有printf -v的格式化字符串似乎是安全的方法。欢迎任何更正,解释和改进。