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

问题描述 投票:1回答:5

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

虽然我可以声明数组Directories0(输入目录)开始,但是我无法以任何方式引用它……结果:错误的替换。显然,Directories1将为depth = 1,Directories2将为depth = 2,依此类推...

下面是一段代码:

let Recurse=4               ## say... variable value ##
[ "$Recurse" ] && let MaxDepth="$Recurse" || let MaxDepth=0
declare -i depth=0

IFS=$'\n'
## declare -a Directories${depth}=("${@}")      ##  <—— doesn't work
## declare -a Directories${depth}="("${@}")"        ##  <—— works if the brackets only are quoted...
## declare -a Directories${depth}=\("${@}"\)        ##  <—— ... or escaped
declare -a "Directories${depth}=("${@}")"
IFS=$' \t\n'

## Nested loop, depth counter increases for each directory depth. I want to stop at a specific depth which is entered as an option ##
for (( depth = 0; depth <= MaxDepth; depth++ )); do                  ## MaxDepth is entered as option ##
    until [ -z "${Directories${depth}[*]}" ]; do                       ## ***** bad substitution error ***** ##
        declare input="$(follow "${Directories${depth}[0]}")"       ## follow is a script that resolves symlinks and Finder aliases ##
        CheckDirectory "${input%/}/"                                  ## check directory ##
        case $? in

        ## Tests passed ##
        0)  if [[ "$Recurse" && "$depth" -lt "$MaxDepth" ]]; then
                IFS=$'\n'
                ## get ready to check sub-directories ##
                declare -a Directories$(( depth + 1 ))="("${Directories$(( depth + 1 ))[@]}" $(find -P "${Directories${depth}[0]}" -type d -mindepth 1 -maxdepth 1 -exec follow '{}' \;))"
                IFS=$' \t\n'
            fi
            true;;

        ## Tests failed ##
        *)  false;;
        esac
        [ $? -eq 0 ] && unset Directories${depth}[0] || exit 1             ## if test fails, exit, if succeeds, move on to next directory ##
        declare -a Directories${depth}="("${Directories${depth}[@]}")"      ## re-shuffle the array to get rid of null value at index 0 ##
        (( element++ ))
    done
done

下面是简化版本,如果您不想通过上面的代码,这是问题的症结所在:

depth=2
declare -a "Directories${depth}=(yo man ma me mo)"
echo "${Directories${depth}[4]}"
    > -bash: ${Directories${depth}[4]}: bad substitution
echo "${Directories2[4]}"
    > mo

解决方案,有人吗?

bash shell variables recursion parameters
5个回答
4
投票

您需要在${}结构内使用文字变量名称。如果要引用其名称在运行时确定的变量,则需要显式进行间接访问。

name="Directories${depth}[4]"
echo ${!name}

这对分配没有帮助。只要您要在当前范围(而不是包围范围)中进行分配,就可以使用内置的typeset进行计算分配。但是,请注意:bash具有启发式功能,可以将看起来像数组分配语法的分配转换为数组分配。这意味着,如果该元素将要存储一个绝对文件名(总是以/开头),那么下面的代码就可以了,但是如果该元素将要存储一个任意文件名(可能是诸如(foo)之类的东西),那么下面的代码就可以了。

typeset "Directories${depth}[4]=new value"

或者,可以使用eval对运行时由任何shell确定名称的变量进行赋值。这样的优势是可以在任何shell中工作,而不仅仅是bash。但是,您需要非常小心:很难正确地引用报价。最好使eval的参数尽可能少。使用一个临时变量来获取存储值。

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

1
投票

使用eval,这有效:

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

mo

0
投票

尝试评估

#!/ bin / bash深度= 2声明-a“ Directorys $ {depth} =(yo man ma me mo)”评估回显“ \ $ {Directory $ {depth} [4]}”回声“ $ {Directories2 [4]}”

0
投票

您几乎在那里:

declare -a Directories${depth}="( yo man ma me mo )"

有效(并且没有eval,顺便说一句)。要访问该值,请使用$ {!}语法:

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

0
投票

也许这是对被问到的(迟来的)答案? (我觉得这个问题并不像问问者所相信的那么清楚。)

#!/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

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

© www.soinside.com 2019 - 2024. All rights reserved.