【问题标题】:Passing variable name as param to function in bash将变量名作为参数传递给 bash 中的函数
【发布时间】:2014-11-20 19:49:45
【问题描述】:

我正在尝试将 3 个具有不同名称的类似文件读取到不同的数组。因为我不想使用不必要的代码,所以我试图创建可以接受数组名称作为参数的函数,但我收到错误“找不到命令”。

hello.sh 文件代码:

    #!/bin/bash
declare -a row_1
declare -a row_2
declare -a row_3


load_array()
{
ROW="$2"
let i=0
while read line; do
    for word in $line; do
    $ROW[$i]=$word        
((++i))
    done
done < $1
}

load_array $1 row_1
load_array $2 row_2
load_array $3 row_3

从终端调用这个文件:sh hello.sh 1.txt 2.txt 3.txt

我得到的错误列表:

hello.sh: line 13: row_1[0]=9: command not found
hello.sh: line 13: row_1[1]=15: command not found
hello.sh: line 13: row_1[2]=13: command not found
hello.sh: line 13: row_2[0]=12: command not found
hello.sh: line 13: row_2[1]=67: command not found
hello.sh: line 13: row_2[2]=63: command not found
hello.sh: line 13: row_3[0]=75: command not found
hello.sh: line 13: row_3[1]=54: command not found
hello.sh: line 13: row_3[2]=23: command not found

【问题讨论】:

标签: bash param variable-names


【解决方案1】:

在赋值语法中,等号左边的必须是变量名(赋值给标量时),或者是变量名后跟方括号中的单词(赋值给数组元素时) .在您的代码中,$ROW[$i]=$word 与此语法不匹配(开头有一个 $,因此不可能是赋值);它只是一个恰好包含字符= 的单词。

在 bash 中,您可以使用 declare 内置函数来分配一个变量,该变量的名称是一些计算的结果,例如变量扩展。请注意,与直接赋值不同,您确实需要在值部分周围加上双引号,以防止$word 上的单词拆分和文件名扩展。如果您在函数中进行赋值并且希望在函数返回后保留该值,则传递选项 -g

declare -g $ROW[$i]="$word"

如果您正在运行没有 declare -g 的旧版本 bash,则可以改用 eval。这将是用于在普通 sh 中分配给动态命名变量的方法。注意正确引用事物:如果 ROW 是例如row_1,那么作为参数传递给eval 的字符串必须是row_1[$i]=$word(要解析和执行的shell 命令)。

eval "$ROW[\$i]=\$word"

【讨论】:

  • 这种声明似乎只进行局部赋值,不允许在全局中使用声明的值。这是我得到的变量的回声:i.imgur.com/SSlUNWL.png
  • @user2816626 啊,抱歉,我没有注意到您需要函数之外的值。添加选项-g(见我的编辑)。
  • 这是一个很好的解决方案。我以前没见过。我会假设您必须使用eval${!ROW} 类型构造。学习已经发生。
  • 现在它说没有这样的选项...'lab3.sh: line 16: declare: -g: invalid option declare: usage: declare [-afFirtx] [-p] [name [=值] ...]'
  • @user2816626 哦,您正在运行一个非常旧版本的 bash?你应该提到这一点。查看我的编辑。
【解决方案2】:

因此,使用现代(bash 4.3+)语法执行此操作的理想方法是:

load_array() {
  declare -n _load_array__row=$2
  declare -a _load_array__line
  _load_array__row=( )
  while read -r -a _load_array__line; do
    _load_array__row+=( "${_load_array__line[@]}" )
  done <"$1"
}

(变量名称很奇怪,以减少与调用函数发生冲突的机会;如果要求将内容加载到名为 ROWline 的变量中,您给出的其他答案将有问题,例如,因为他们在描述目的地时会引用局部变量而不是全局变量)。


与 bash 3.2(Apple 发布的旧版本)兼容的类似机制,避免了与内部循环相关的性能损失和与 glob 扩展相关的错误(请参阅您的原始代码对包含 * 的行的作用!)如下:

load_array() {
  local -a _load_array__array=( )
  local -a _load_array__line
  while read -r -a _load_array__line; do
    _load_array__array+=( "${_load_array__line[@]}" )
  done <"$1"
  eval "$2=( \"\${_load_array__array[@]}\" )"
}

【讨论】:

    猜你喜欢
    • 2018-05-25
    • 1970-01-01
    • 1970-01-01
    • 2013-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    相关资源
    最近更新 更多