2011-08-22 63 views
1

我编写了一个脚本,我希望用户输入一个目录或多个目录,并且每个目录都检查一些对此讨论不重要的内容。所有的内部目录也被检查到指定的深度。参数名称中的Bash数组参数扩展:错误替换

虽然我可以声明数组Directories0(输入目录)开始,但我无法以任何方式引用它...... result:错误的替换。显然,Directories1将深度= 1,Directories2是深度= 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 

解决方案,任何人吗?

- Aesthir

回答

0

尝试的eval

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

+0

用'的问题eval'是我似乎无法做**任何事情*阵列***。无论IFS设置为什么,eval都会分解包含空格的元素。我尝试过,但无济于事...这是一个挑战,试着让我发布的代码作为使用'eval'工作的问题......我能想到的唯一方法就是循环遍历每个元素我希望使用eval。对于初学者,***没有循环*,使用'eval'从底部的第4行开始工作(重新洗牌)。如果'eval'真的*可以*做到这一点,我相信这将是一个简单的一行。** – Aesthir

1

使用eval,这个工程:

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

mo 
+0

你好,简单的例子工作,没有空格,但这个简单的例子是无处可寻我的代码,它只是用来说明我的问题。问题的关键在于代码中,如果你不想让整个事情发挥作用,那么**将重点放在从底部开始的第4行,并且使用'eval' **循环遍历每个元素。请记住,这些值不是简单的“mo”,而是具有空格和Unicode字符的长行与基本拉丁文不同。我提出了一个概念,即“eval”不**工作,但也许我错误地使用了它。 – Aesthir

3

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

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

这对分配没有帮助。只要您在当前范围内进行分配(而不是在范围内),则可以使用内置的typeset进行计算分配。但是,要小心:bash有一个启发式的方法,它可以将看起来像数组赋值语法的赋值转换为数组赋值。这意味着如果元素要存储绝对文件名(始终以/开头),但是如果要存储任意文件名(可能类似于(foo)),那么以下代码是可以的。

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

是,可替代地,可以执行分配给其名称在运行时通过使用eval确定与任何壳的变量。这具有在任何shell中工作的优势,而不仅仅是bash。但是,您需要非常小心:很难获得正确的引用。最好让eval的参数尽可能少。使用临时变量来获取存储值。

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

好的,在炸掉我的代码后(现在大于3倍......并且启动慢得多),我通过许多循环将所有数组转换为常规参数赋值。很多不必要的代码。 'eval'和间接引用都很好,但是对于数组,包括赋值和引用,都做得很好。有没有**没有办法**一次处理数组作业?像:'typeset -a Directories $ {depth} =(“$ {Array [@]}”)'?或者,我需要:'typeset -a目录$ {depth} =(“$ {目录$ {深度} [@]}”)'使用'eval'?间接参考?一些其他的诡计也许另一种语言? Perl的? C? PHP的? – Aesthir

+0

@Aesthir的确,我认为Perl就是你要找的东西。 – Gilles

+0

_谢谢你Giles_,因为你的思想很清楚,你需要花一分多钟才能打出来。我已经研究了相当长的一段时间,尝试了很多(100s)快速测试,主要是单线程,修改语法或从不同角度处理问题......但仍然卡住了。如果Perl可以提供解决方案,我不知道。 Beyone Perl正则表达式,我不知道关于Perl的第一件事(用法/语法/命令/等)。 **您可以提供一些Perl代码**,例如,像脚本底部的第4行那样重新索引数组?我敢肯定这将是一个单线...... – Aesthir

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 

如果我误解了这个问题,好了,我并不十分惊讶:-)