54

定義された配列に対してforループを実行する順序を逆にするにはどうすればよいですか?

配列を反復処理するために、私はこれを行っています:

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

配列の順番を逆にできる機能はありますか?

私が持っていた考えの1つは、転置インデックスのシーケンスを生成し、この転置インデックスを使用して要素を呼び出すことでしたが、より迅速な代替手段、または少なくとも読みやすい方法があるかもしれません。

4

8 に答える 8

73

Cスタイルのforループを使用できます。

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
于 2012-11-13T11:44:35.557 に答える
26

tacを使用できます。これはcat、線を逆にするという意味では逆です。

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

# four
# three
# two
# one
于 2012-11-13T11:51:44.533 に答える
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[@]}"

これは可能な配列を処理するはずだと思います。

そこで何が起こっているかに興味があるなら、まずここを見てみることをお勧めします。それなら多分ここ、間違いなくここ、そして時間があればここここ

これらすべての回答で、ヒアドキュメント(および他の多くのドキュメント)のさまざまな側面について説明します。"_$1"たとえば、変数を2回評価する方法について説明します。これは上記で行われ、1つは、5行または6行で名前が付けられた別の関数をグローバルに宣言する関数を宣言します_$1() { func body ; }正しく使えばかなり重宝します。

ウェル間の自動切り替えに関しては、bash/zsh, それは別のことですが、非常に単純です。ここを参照してください。

于 2014-03-21T12:18:03.117 に答える
4

これはどう:

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; }

そしてそれをこのように使用します:

reverse "${MYARRAY[@]}" && for i in "${reversed[@]}"; do echo $i; done
于 2016-04-16T23:50:06.183 に答える
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

于 2017-08-26T00:23:01.410 に答える
1

順次数値配列について話している場合(たとえば、bash履歴を削除する場合)、たとえば、これを逆の順序でリストすることができます。

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

これはちょっとオフトピックだと思います。申し訳ありませんが、おそらく言及する価値があると思いました。

于 2015-08-25T22:17:53.757 に答える
1

そのようなものにはワンライナーの使用を制限し、代わりにシェルまたはスクリプトにソースされる関数を作成することをお勧めします。これは、関数を参照することで複数の配列を渡すことができる新しいバージョンの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

...ただし、この手法では、関数が不純(副作用がある)になることに注意してください。つまり、Bashスクリプトの考え方では、デバッグ_list_new_list困難になる可能性があります...現在の例でも考慮されていません再実行reverse_arrayして_new_list、複数回追加される可能性があります。これは望ましい場合と望ましくない場合があります。

于 2019-08-18T07:58:05.790 に答える
1

使用を検討することもできます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
于 2019-12-04T17:36:28.550 に答える