Подтвердить что ты не робот

Как отменить массив в цикле bash onliner FOR?

Как я могу отменить порядок, в котором я выполняю цикл for для определенного массива

Чтобы выполнить итерацию по массиву, я делаю это:

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

Есть ли функция, в которой я могу изменить порядок массива?

Мне показалось, что нужно создать последовательность инвертированных индексов и вызвать элементы с помощью этого обратного индекса, но, возможно, есть более быстрая альтернатива или, по крайней мере, легче читать.

4b9b3361

Ответ 1

Вы можете использовать цикл цикла 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

Ответ 2

Вы можете использовать tac, что является противоположностью cat в том смысле, что оно меняет направление строк.

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

# four
# three
# two
# one

Ответ 3

_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" всего за 5 или 6 строк, большинство из которых были _$1() { func body ; }. Это очень удобно, если вы используете его правильно.

Относительно автоматического переключения между bash/zsh, хорошо, что-то другое, но очень простое. См. здесь.

Ответ 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

Ответ 5

Просто как строка:

% 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

Ответ 6

Если вы говорите о последовательном числовом массиве (скажем, для удаления истории bash), вы можете просто перечислить это в обратном порядке, например:

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

Я понимаю, что это отчасти не по теме, и я прошу прощения за это, однако я подумал, что, вероятно, стоит упомянуть.

Ответ 7

Я бы посоветовал ограничить использование одной строки для таких вещей и вместо этого написать функцию, которая была бы включена в вашу оболочку или скрипт. Вот пример для более новых версий 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 несколько раз; что может или не может быть желательным.