bash の連想配列から逆順にファイルを印刷する

bash の連想配列から逆順にファイルを印刷する
for key in ${!current_file[@]} 
    do
      echo $key      
     done

bash で current_file を以下のように宣言します。

declare -A current_file

キーをファイルとして挿入し、サイズを値として current_file に挿入します。for ループの出力は次のようになります。

file2
file1

次のように印刷したい:

file1 
file2

どうすればこのように印刷できますか?

答え1

アルファベット順にソートされたキーのリストを印刷するには、GNU を想定してsort次のようにします。

printf '%s\0' "${!hash[@]}" | sort -z | tr '\0' '\n'

または、ソートされたキーのリストを反復処理するには、次のようにします。

while IFS= read -rd '' -u3 key; do
  something with "${hash[$key]}"
done 3< <(printf '%s\0' "${!hash[@]}" | sort -z)

キーに改行文字が含まれないことを保証できる場合は、次のように簡略化できます。

printf '%s\n' "${!hash[@]}" | sort

の場合zsh、次のようになります。

printf "%s\n" "${(ko@)hash}"

(kキーを取得し、oそのリストを順序付けし、@空のキーがある場合はそれを保存するために二重引用符で囲みます (bash現時点では、空のキーを持つハッシュ要素を持つことができないという制限があることに注意してください))。

そして、それらをループするには:

for key in "${(ko@)hash}"; do
  something with "$hash[$key]"
done

上記の最後の例外を除いて、ハッシュには少なくとも 1 つの要素が含まれていると想定していることに注意してください (引数がない場合でも、空のキーを持つ要素があるかのようにprintf '%s\0'出力されます)。\0

いずれにしても、${!current_file[@]}引用符なしで記述すると、キーのリストに対して split+glob 演算子が呼び出されるため、ほとんど意味がありません。

答え2

連想配列は、bash一般的な言語のハッシュ/辞書のようなもので、それらと同様に順序付けられていません (実際には内部ハッシュ値に従って順序付けられています)。そのため、(連想) 配列キーを反復処理している間、出力が (一般的に) ソートされていることを期待することはできません。

自分でソートする必要があります。たとえば、STDOUT を次の STDIN に送信しますsort

for key in ${!current_file[@]}; do
    echo $key      
done | sort 

または同様のもの。


連想配列のキー/値に対して順序に基づいた操作を実行できるように順序を維持したい場合は、挿入の参照として別のインデックス付き配列を保持できます。次に基本的な考え方を示します。

## Associative array `foo`
$ declare -A foo=([spam]=egg [baz]=cool)

## Reference indexed array `bar` containing the keys of `foo` sequentially indexed
$ bar=(spam baz)

## Retrieving in forward order
$ for i in "${bar[@]}"; do echo "$i :: ${foo[$i]}"; done
spam :: egg
baz :: cool

## Retrieving in reverse order
$ for ((i=${#bar[@]}-1; i>=0; i--)); do idx="${bar[$i]}"; echo "$idx :: ${foo[$idx]}"; done
baz :: cool
spam :: egg

関連情報