参数名称内的Bash数组参数扩展:错误替换

参数名称内的Bash数组参数扩展:错误替换,bash,shell,variables,recursion,parameters,Bash,Shell,Variables,Recursion,Parameters,我编写了一个脚本,希望用户输入一个或多个目录,并检查每个目录是否有与本次讨论无关的内容。所有内部目录也会检查到指定的深度 虽然我可以声明要启动的输入目录的数组方向,但我不能以任何方式引用它。。。结果:替换不良。显然,Directories1的深度为1,Directories2的深度为2,依此类推 下面是一段代码: 解决方案,有人吗?试试评估 #!/bin/bash depth=2 declare -a "Directories${depth}=(yo man ma me mo)" eva

我编写了一个脚本,希望用户输入一个或多个目录,并检查每个目录是否有与本次讨论无关的内容。所有内部目录也会检查到指定的深度

虽然我可以声明要启动的输入目录的数组方向,但我不能以任何方式引用它。。。结果:替换不良。显然,Directories1的深度为1,Directories2的深度为2,依此类推

下面是一段代码:

解决方案,有人吗?

试试评估

#!/bin/bash depth=2 declare -a "Directories${depth}=(yo man ma me mo)" eval echo "\${Directories${depth}[4]}" echo "${Directories2[4]}" 试评估

#!/bin/bash depth=2 declare -a "Directories${depth}=(yo man ma me mo)" eval echo "\${Directories${depth}[4]}" echo "${Directories2[4]}" 使用eval,这将起到以下作用:

eval echo \${Directories${depth}[4]}

mo
使用eval,这将起到以下作用:

eval echo \${Directories${depth}[4]}

mo

在${}构造中需要一个文字变量名。如果您想引用一个名称在运行时确定的变量,您需要显式地经历一个间接级别

name="Directories${depth}[4]"
echo ${!name}
这对作业没有帮助。只要在当前范围内而不是在包含范围内赋值,就可以使用内置的排版进行计算赋值。但是,要小心:bash有一种启发式方法,它可以将看起来像数组赋值语法的赋值转换为数组赋值。这意味着,如果元素要存储一个始终以/开头的绝对文件名,那么下面的代码是可以的,但如果元素要存储一个类似foo的任意文件名,那么下面的代码就不可以了

或者,可以使用eval对一个变量执行赋值,该变量的名称在运行时由任何shell确定。它的优点是可以在任何shell中工作,而不仅仅是bash。不过,你需要非常小心:很难得到正确的报价。最好让eval的论点尽可能少做。使用临时变量获取并存储值

eval "tmp=\${Directories${depth}[4]}"
echo "$tmp"
tmp="new value"
eval "Directories${depth}[4]=\$tmp"

在${}构造中需要一个文字变量名。如果您想引用一个名称在运行时确定的变量,您需要显式地经历一个间接级别

name="Directories${depth}[4]"
echo ${!name}
这对作业没有帮助。只要在当前范围内而不是在包含范围内赋值,就可以使用内置的排版进行计算赋值。但是,要小心:bash有一种启发式方法,它可以将看起来像数组赋值语法的赋值转换为数组赋值。这意味着,如果元素要存储一个始终以/开头的绝对文件名,那么下面的代码是可以的,但如果元素要存储一个类似foo的任意文件名,那么下面的代码就不可以了

或者,可以使用eval对一个变量执行赋值,该变量的名称在运行时由任何shell确定。它的优点是可以在任何shell中工作,而不仅仅是bash。不过,你需要非常小心:很难得到正确的报价。最好让eval的论点尽可能少做。使用临时变量获取并存储值

eval "tmp=\${Directories${depth}[4]}"
echo "$tmp"
tmp="new value"
eval "Directories${depth}[4]=\$tmp"
你就快到了:

declare -a Directories${depth}="( yo man ma me mo )"
工作且不带eval,顺便说一句。要访问该值,请使用${!}语法:

temp=Directories$depth[@]
echo ${!temp}
你就快到了:

declare -a Directories${depth}="( yo man ma me mo )"
工作且不带eval,顺便说一句。要访问该值,请使用${!}语法:

temp=Directories$depth[@]
echo ${!temp}

也许这是对所问问题的一个姗姗来迟的回答?这个问题不像提问者认为的那么清楚,我觉得

#!/bin/bash

for depth in {0..5}
do
  var_value=(yo man ma me mo "last value")
  var_name="directories${depth}"
  eval "${var_name}=\"${var_value[${depth}]}\""

  value="directories${depth}"
  printf "directories{$depth} = ${!value}"

  [ $depth -eq 0 ] && printf "  \t directories0=$directories0\n"
  [ $depth -eq 1 ] && printf "  \t directories1=$directories1\n"
  [ $depth -eq 2 ] && printf "  \t directories2=$directories2\n"
  [ $depth -eq 3 ] && printf "  \t directories3=$directories3\n"
  [ $depth -eq 4 ] && printf "  \t directories4=$directories4\n"
  [ $depth -eq 5 ] && printf "  \t directories5=$directories5\n"
done
产生:

directories{0} = yo      directories0=yo
directories{1} = man     directories1=man
directories{2} = ma      directories2=ma
directories{3} = me      directories3=me
directories{4} = mo      directories4=mo
directories{5} = last value      directories5=last value
要点是,如果一个变量名由另一个变量组成,如何为它赋值。例如,如果设置foobar=value是将变量设置为值的正常方式,那么如果x=foo和y=bar,如何设置${x}${y}=value=>例如:

  foobar=test
  echo $foobar
  > test

  x=foo
  y=bar
  eval "export ${x}${y}=\"value\""
  echo $foobar
  > value

如果我误解了这个问题,那么,我并不感到非常惊讶:-

也许这是对所问问题的一个迟到的回答?这个问题不像提问者认为的那么清楚,我觉得

#!/bin/bash

for depth in {0..5}
do
  var_value=(yo man ma me mo "last value")
  var_name="directories${depth}"
  eval "${var_name}=\"${var_value[${depth}]}\""

  value="directories${depth}"
  printf "directories{$depth} = ${!value}"

  [ $depth -eq 0 ] && printf "  \t directories0=$directories0\n"
  [ $depth -eq 1 ] && printf "  \t directories1=$directories1\n"
  [ $depth -eq 2 ] && printf "  \t directories2=$directories2\n"
  [ $depth -eq 3 ] && printf "  \t directories3=$directories3\n"
  [ $depth -eq 4 ] && printf "  \t directories4=$directories4\n"
  [ $depth -eq 5 ] && printf "  \t directories5=$directories5\n"
done
产生:

directories{0} = yo      directories0=yo
directories{1} = man     directories1=man
directories{2} = ma      directories2=ma
directories{3} = me      directories3=me
directories{4} = mo      directories4=mo
directories{5} = last value      directories5=last value
要点是,如果一个变量名由另一个变量组成,如何为它赋值。例如,如果设置foobar=value是将变量设置为值的正常方式,那么如果x=foo和y=bar,如何设置${x}${y}=value=>例如:

  foobar=test
  echo $foobar
  > test

  x=foo
  y=bar
  eval "export ${x}${y}=\"value\""
  echo $foobar
  > value

如果我误解了这个问题,那么,我并不感到非常惊讶:-

好吧,现在我的代码放大了3倍。。。启动速度要慢得多,我通过许多循环将所有数组转换为常规参数分配。很多不必要的代码。eval和间接引用都很好,但都适用于数组,包括赋值和引用。是否无法同时处理所有数组分配?比如:typeset-a目录${depth}=${Array[@]}?或者,我需要的是:typeset-a目录${depth}=${Directories${depth}[@]}使用eval?间接引用?还有别的把戏吗?也许是另一种语言?perl?Cphp?@Aesthir确实,我认为Perl是您所需要的。感谢Giles深思熟虑的回答,cleary花了一分钟多的时间打印出来。我已经研究了相当长的一段时间,并尝试了100多次快速测试,主要是使用一行程序,修改语法或从di解决问题
不同的角度。。。但我还是被卡住了。如果Perl能够提供解决方案,我就不知道了。Beyone Perl regex,我不知道Perl用法/语法/命令等的第一件事。你能提供一些Perl代码,比如说,在我的脚本底部的第4行重新索引数组吗?我相信它将是一个一行程序…@Aesthir Perl最初是作为shell和awk绑定在一起的,从那时起,它已经发展了很多。它对嵌套数据结构提供了良好的支持,这正是您所追求的,即按深度和广度索引的目录。我不知道“重新索引数组”是什么意思,但是这里的赋值等价于$Directories[$depth][4]=如果更改现有元素,则为新值,或者push@{$Directories[$depth]},要附加到现有数组末尾的新值。通过对数组重新编制索引,我的意思是如何在原始脚本中从下到下的第四行获得这一行,以使用bash或Perl,这并不重要:declare-a Directories${depth}=${Directories${depth}[@]}基本上,我希望运行的命令是:typeset-a Directories0=${Directories0[@]}。。。我怎样才能让它适用于任何语言?好吧,在我的代码放大3倍之后。。。启动速度要慢得多,我通过许多循环将所有数组转换为常规参数分配。很多不必要的代码。eval和间接引用都很好,但都适用于数组,包括赋值和引用。是否无法同时处理所有数组分配?比如:typeset-a目录${depth}=${Array[@]}?或者,我需要的是:typeset-a目录${depth}=${Directories${depth}[@]}使用eval?间接引用?还有别的把戏吗?也许是另一种语言?perl?Cphp?@Aesthir确实,我认为Perl是您所需要的。感谢Giles深思熟虑的回答,cleary花了一分钟多的时间打印出来。我已经研究了很长一段时间,并尝试了100多个快速测试,主要是一行程序,修改语法或从不同角度处理问题。。。但我还是被卡住了。如果Perl能够提供解决方案,我就不知道了。Beyone Perl regex,我不知道Perl用法/语法/命令等的第一件事。你能提供一些Perl代码,比如说,在我的脚本底部的第4行重新索引数组吗?我相信它将是一个一行程序…@Aesthir Perl最初是作为shell和awk绑定在一起的,从那时起,它已经发展了很多。它对嵌套数据结构提供了良好的支持,这正是您所追求的,即按深度和广度索引的目录。我不知道“重新索引数组”是什么意思,但是这里的赋值等价于$Directories[$depth][4]=如果更改现有元素,则为新值,或者push@{$Directories[$depth]},要附加到现有数组末尾的新值。通过对数组重新编制索引,我的意思是如何在原始脚本中从下到下的第四行获得这一行,以使用bash或Perl,这并不重要:declare-a Directories${depth}=${Directories${depth}[@]}基本上,我希望运行的命令是:typeset-a Directories0=${Directories0[@]}。。。我如何让它适用于任何语言?是的,好的,这个简单的例子有效,没有空格。但是这个简单的例子在我的代码中找不到,它只是用来说明我的问题。问题的关键在于代码,如果您不想让整个过程正常工作,那么请关注底部的第4行,并在不使用eval循环遍历每个元素的情况下正常工作。请记住,这些值不仅仅是mo,而是带有空格和Unicode字符的长线,就像基本拉丁语一样。我提出了eval不起作用的概念,但可能我用错了。是的,好的,这个简单的例子有效,没有空格。但是这个简单的例子在我的代码中找不到,它只是用来说明我的问题。问题的关键在于代码,如果您不想让整个过程正常工作,那么请关注底部的第4行,并在不使用eval循环遍历每个元素的情况下正常工作。请记住,这些值不仅仅是mo,而是带有空格和Unicode字符的长线,就像基本拉丁语一样。我提出了eval不起作用的概念,但可能我用错了。eval的问题是,我似乎不能对数组做任何事情。无论IFS设置为什么,eval都会分解包含空格的元素。我试了又试,但是没有用。。。这里有一个挑战,试着让我发布的代码作为一个问题来使用eval。。。我能想到的唯一一件事是,每当我希望使用eval时,循环遍历每个元素。对于初学者,在不循环的情况下,使用eval从底部获得第4行以重新洗牌。如果eval真的能做到这一点,我相信这将是一个简单的单行程序。eval的问题是我似乎对数组无能为力。无论IFS设置为什么,eval都会分解包含空格的元素。我试了又试,但是没有用。。。这里有一个挑战,试着让我发布的代码作为一个问题来使用eval。。。我唯一能做的事 每次我想使用eval时,都要循环遍历每个元素。对于初学者,在不循环的情况下,使用eval从底部获得第4行以重新洗牌。如果eval真的能做到这一点,我相信这将是一个简单的一行。