为什么我不能指定包含bash数组变量长度的序列?

为什么我不能指定包含bash数组变量长度的序列?,bash,shell,Bash,Shell,我正在编写一个脚本,它在一系列目录中查找是否存在文件,找到文件后,通过pushd将其推送到目录堆栈上。dirs命令非常讨厌,我偶然发现了它的内容的bash变量形式,$DIRSTACK $DIRSTACK是堆栈中的目录数组。它总是保证有一个条目,即当前工作目录,然后是推送目录 我试图遍历目录列表,但似乎无法使for循环接受我试图自动生成的序列长度: for i in {1..${#DIRSTACK[*]}}; do echo ${DIRSTACK[$i]} done 执行时,bash会失败,

我正在编写一个脚本,它在一系列目录中查找是否存在文件,找到文件后,通过
pushd
将其推送到目录堆栈上。
dirs
命令非常讨厌,我偶然发现了它的内容的bash变量形式,
$DIRSTACK

$DIRSTACK
是堆栈中的目录数组。它总是保证有一个条目,即当前工作目录,然后是推送目录

我试图遍历目录列表,但似乎无法使for循环接受我试图自动生成的序列长度:

for i in {1..${#DIRSTACK[*]}}; do
  echo ${DIRSTACK[$i]}
done
执行时,bash会失败,并出现以下错误:

line 72: {1..2}: syntax error: operand expected (error token is "{1..2}")
老实说,我被难住了,因为我已经在{1..5}脚本中手动编写了很多次
而没有出现问题,并且给出了错误消息,看起来数组项扩展的数量完全按照我希望的那样工作


为什么会发生此错误?

如果支架展开中包含参数,则支架展开将无法正常工作。这是因为在本例中,参数
DIRSTACK
,只有在大括号展开后才会展开

从bash手册页:

支架展开在任何其他展开之前执行,并且 结果中保留了其他扩展的特殊字符。 这是严格的文本。Bash不应用任何语法 释义要在语境或文本之间展开 支架

如果您只是想在阵列上循环,为什么不使用以下命令

for i in "${DIRSTACK[@]}"
do
    echo $i
done
或者,如果要显式使用数组的长度:

for (( i = 0 ; i < ${#DIRSTACK[@]} ; i++ ))
do
    echo ${DIRSTACK[$i]}
done
((i=0;i<${#DIRSTACK[@]};i++)的

做
echo${DIRSTACK[$i]}
完成
序列表达式的类似构造是使用
seq(1)
命令

对于您的具体情况,您可以使用:

for i in $(seq ${#DIRSTACK[*]}); do
  echo ${DIRSTACK[$i]}
done
但是,考虑到您对@dogbane答案的评论,这仍然不能满足您的要求,因为您仍然在迭代数组中的元素数,但索引已经过了末尾

通过使用bash的子字符串扩展,您可以轻松实现所需的功能,该扩展也适用于阵列

for dir in "${DIRSTACK[@]:1}" ; do
  echo $dir
done

很高兴看到Stack Overflow的语法颜色有一个bug。关于错误消息的混淆是因为错误来自
echo
行,而不是
for
行。如果
回显“$i”
,您将看到
{1..2}
被输出。正如dogbane所说,扩展的顺序是个问题。我没有意识到bash支持长形式for循环。不幸的是,我不想以第一种形式循环数组的原因是我必须跳过第一项,因为当前的工作目录对我来说毫无价值。这就是为什么我从1而不是0开始序列。我很想检查一下所有的项目,但因为我必须排除一个[…]@VxJasonxV:然后在“${DIRSTACK[@]:1}”中为我使用
@GordonDavisson完全这样做。谢谢:D!另一方面,有许多具有支撑/序列展开的壳。只有Bash首先执行它们。两者都有优点/缺点-这可以说是缺点之一。无论如何,它们不应该用于迭代。@ormaj如果我理解正确的话,您提到这一点是为了便于移植。注意,我做了一个显式的#/bin/bash位于文件顶部,而不仅仅是#/bin/sh。如果我不明白,请纠正我。@denniswillamson这就是我最后使用的内容。但肯定会改变Gordon Davidson/camh为子字符串扩展提供的建议。@Dennis Williamson:
seq 5
seq 15
有何不同?根据手册页,它们是相同的,那么为什么要添加额外的字符呢?哎呀,对不起,我在想
seq
did基于0的序列。我很少使用它,只是弄错了。下次:
man
先翻页,然后键入注释(或不键入)。