Imprimir arquivos na ordem inversa de um array associativo no bash

Imprimir arquivos na ordem inversa de um array associativo no bash
for key in ${!current_file[@]} 
    do
      echo $key      
     done

Declaro current_file como abaixo no bash:

declare -A current_file

insira a chave como um arquivo e o tamanho como valor em arquivo_atual. Saída das impressões do loop for:

file2
file1

Quero imprimir como:

file1 
file2

Como posso imprimir assim?

Responder1

Para imprimir a lista de chaves ordenadas em ordem alfabética, e assumindo GNU sort, você poderia fazer:

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

Ou para iterar na lista classificada de chaves:

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

Se você puder garantir que as chaves não conterão caracteres de nova linha, poderá simplificá-las para:

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

Com zsh, isso seria:

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

( kpara obter as chaves, opara ordenar essa lista, @entre aspas duplas para preservar a chave vazia, se houver (observe que bashatualmente tem uma limitação: não pode ter um elemento hash com uma chave vazia)).

E para fazer um loop sobre eles:

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

Observe que, exceto pelo último acima, estamos assumindo que o hash contém pelo menos um elemento (já que printf '%s\0'sem nenhum argumento ainda seria gerado \0como se houvesse um elemento com uma chave vazia).

Em qualquer caso, escrever ${!current_file[@]}sem aspas faz muito pouco sentido, pois invoca o operador split+glob nessa lista de chaves.

Responder2

A matriz associativa bashé como hashes/dicionários em linguagens típicas e, como eles, não é ordenada (na verdade, ordenada de acordo com o valor do hash interno). Portanto, você não pode esperar que a saída seja (geralmente) classificada durante a iteração nas chaves da matriz (associativas).

Você precisa classificar você mesmo, por exemplo, enviando o STDOUT para o STDIN de sort:

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

ou algo semelhante.


Se você deseja manter um pedido para poder realizar qualquer operação baseada em pedido nas chaves/valores do array associativo, você pode manter outro array indexado como referência de inserção. O seguinte deve lhe dar uma ideia básica:

## 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

informação relacionada