如何在bash内联FOR循环中反转数组?

时间:2012-11-13 11:38:05

标签: bash

如何反转我为定义的数组执行for循环的顺序

要遍历数组我正在这样做:

$ export MYARRAY=("one" "two" "three" "four")
$ for i in ${MYARRAY[@]}; do echo $i;done
one
two
three
four

是否有可以反转数组顺序的函数?

我有一个想法是生成一系列反向索引并使用这个反向索引来调用元素,但也许有更快的替代方法,或者至少更容易阅读。

8 个答案:

答案 0 :(得分:57)

您可以使用C风格的循环:

for (( idx=${#MYARRAY[@]}-1 ; idx>=0 ; idx-- )) ; do
    echo "${MYARRAY[idx]}"
done

对于具有“孔”的数组,元素${#arr[@]}的数量与最后一个元素的索引不对应。您可以创建另一个索引数组并以相同的方式向后移动:

#! /bin/bash
arr[2]=a
arr[7]=b

echo ${#arr[@]}  # only 2!!

indices=( ${!arr[@]} )
for ((i=${#indices[@]} - 1; i >= 0; i--)) ; do
    echo "${arr[indices[i]]}"
done

答案 1 :(得分:22)

您可以使用tac,它与cat相反,意味着它会反转这些行。

MYARRAY=("one" "two" "three" "four")
for item in "$MYARRAY"; do
   echo "$item"; 
done | tac

# four
# three
# two
# one

答案 2 :(得分:5)

_arr+=( '"${_arrev} is an actual "${array[@]}"' )  ⏎
_arr+=( '"${_arrev} is created as a result"' )
_arr+=( '"of reversing the key order in"' )
_arr+=( '"this "${_arr}. It handles zsh and"' )
_arr+=( '"bash arrays intelligently by tracking"' )
_arr+=( '"shell "$ENV." quotes=fine ( i hope ) "' )

. <<REVERSE /dev/stdin                    ⏎
    _arrev=( $(: $((l=${#_arr[@]}${ZSH_VERSION++1})) ; printf '"${_arr[$(('$l'-%d))]}" ' `seq 1 $l`) )
REVERSE

echo ; printf %s\\n ${_arrev}

"shell "$ENV." quotes=fine ( i hope ) "
"bash arrays intelligently by tracking"
"this "${_arr}. It handles zsh and"
"of reversing the key order in"
"${_arrev} is created as a result"
"${_arrev} is an actual "${array[@]}"

我认为这应该处理任何可能的数组。

如果你对那里发生的事情感兴趣,我建议你先看看here。然后可能是here,绝对是here,如果你有时间,herehere

在所有这些答案中,我讨论的不同 here-document (以及许多其他的)的各个方面,您可以利用它们。例如,我讨论了两次评估变量,这是在上面完成的,并在一个声明一个函数,该函数在5或6行中全局声明另一个名为 "_$1" 的函数 - 其中大多数是< em> _$1() { func body ; }。如果你正确使用它,它会非常方便。

关于 bash/zsh, 之间的自动切换,这是另一回事,但也非常简单。请参阅here

答案 3 :(得分:3)

这个怎么样:

dev

输出结果为:

for i in `printf '%s\n' "${MYARRAY[@]}"|tac`; do echo $i; done

限制:如果数组包含换行符,则不起作用。 作为一种解决方法,您可以实现功能:

four
three
two
one

并以这种方式使用它:

reverse(){ reversed=();local i;for ((i=$#;i>0;i--)); do reversed+=("${!i}");done; }

答案 4 :(得分:2)

简单如字符串:

% unset c; a="1 2 3 4 5"; for b in $a; do c="$b $c"; done; echo $c

5 4 3 2 1

您确定需要数组语法??:

 % unset c; declare -a c; a=(1 2 3 4 5); i=0; for b in ${a[*]}; \
    do c[$((${#a[@]}-$i))]=$b; i=$(($i+1)); done; echo ${c[*]}

5 4 3 2 1

答案 5 :(得分:1)

如果您正在谈论顺序数字数组(比如删除bash历史记录),您可以按相反的顺序列出这个例子:

for i in {16..10}; do history -d $i; done

我意识到这是一个偏离主题的事情,我为此道歉,但我认为这可能值得一提。

答案 6 :(得分:0)

我建议限制这种情况的单行用法,而应该编写源于您的Shell或脚本的函数。这是更新版本的Bash的示例,可以通过引用一个函数来传递多个数组...

reverse_array(){
  local -n _source_array_ref="${1}"
  local -n _destination_array_ref="${2}"

  for ((_index=${#_source_array_ref[@]}-1; _index>=0; _index--)); do
    _destination_array_ref+=("${_source_array_ref[$_index]}")
  done
}


_list=(spam ham space)
_new_list=()

reverse_array '_list' '_new_list'

printf '%s\n' "${_new_list[@]}"
#> space
#> ham
#> spam

...但是,请注意,使用此技术时,它会产生不纯(具有副作用)的功能,这意味着调试_list_new_list可以在使用Bash脚本编写思维时会变得很困难...目前的示例也没有考虑到人们可能会重新运行reverse_array并最终将_new_list附加多次;可能会或可能不会。

答案 7 :(得分:0)

您还可以考虑使用seq

MYARRAY=("one" "two" "three" "four")

for i in $(seq $((${#MYARRAY[@]} - 1)) -1 0); do
    echo ${MYARRAY[$i]}
done

在freebsd中,您可以省略-1增量参数:

for i in $(seq $((${#MYARRAY[@]} - 1)) 0); do
    echo ${MYARRAY[$i]}
done