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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13360091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:57:24  来源:igfitidea点击:

How to reverse array in bash onliner FOR loop?

bash

提问by pedrosaurio

How can I reverse the order in which I perform a for loop for a defined array

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

To iterate through the array I am doing this:

为了遍历数组,我这样做:

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

Is there a function where I can reverse the order of the array?

有没有可以颠倒数组顺序的函数?

One thought I had is to generate a sequence of inverted indexes and call the elements by using this reversed index but maybe there is a quicker alternative, or at least easier to read.

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

回答by choroba

You can use the C-style for loop:

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

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

For an array with "holes", the number of elements ${#arr[@]}doesn't correspond to the index of the last element. You can create another array of indices and walk it backwards in the same way:

对于具有“孔”的数组,元素数量${#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

回答by bereal

You can use tac, which is an opposite of catin sense that it reverses the lines.

您可以使用tac,这与cat它反转线条的意义相反。

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

# four
# three
# two
# one

回答by mikeserv

_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[@]}"

This should handle any possible array, I think.

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

If you're interested in what's going on up there, I suggest you have a look herefirst. Then maybe here, definitely here, and, if you've got the time, hereand here.

如果你对上面发生的事情感兴趣,我建议你先看看这里。那么也许在这里,绝对在这里,如果你有时间,在这里这里

In all of those answers I discuss different aspects of the here-document (and in many others)which you can use to your advantage. For instance I discuss twice-evaluating variables, which is done above, and in one declare a function that globally declares another function named "_$1"in just 5 or 6 lines - most of which were _$1() { func body ; }.It's pretty handy if you use it correctly.

在所有这些答案中,我讨论了此处文档(以及许多其他文档)的不同方面,您可以利用这些方面的优势。例如,我讨论了两次求值变量,这是在上面完成的,并且在一个函数中声明了一个函数,该函数全局声明了另一个"_$1"仅用 5 或 6 行命名的函数——其中大部分是_$1() { func body ; }. 如果您正确使用它,它会非常方便。

Regarding the auto-switch between bash/zsh,well that's something else, but very simple as well. See here.

关于bash/zsh,井之间的自动切换是另一回事,但也很简单。见这里

回答by Alek

How about this:

这个怎么样:

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

The output is:

输出是:

four
three
two
one

Limitation: doesn't work if array contain newlines. As a workaround you may implement function:

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

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

and use it this way:

并以这种方式使用它:

reverse "${MYARRAY[@]}" && for i in "${reversed[@]}"; do echo $i; done

回答by Johan Snowgoose

Simple as a string:

简单的字符串:

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

5 4 3 2 1

5 4 3 2 1

You sure you want array syntax??:

你确定你想要数组语法??:

 % 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 4 3 2 1

回答by Robert

If you are talking about a sequential numerical array (say to delete bash history) you can just list this in reverse order for instance:

如果你在谈论一个连续的数字数组(比如删除 bash 历史),你可以以相反的顺序列出它,例如:

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

I realize that this is kind of off topic and I apologize for that however I figured that it was probably worth mentioning.

我意识到这有点偏离主题,我为此道歉,但我认为这可能值得一提。

回答by S0AndS0

I'd advise limiting one-liner usage for such things and instead write a function that's sourced into your shell or script. Here's an example for newer versions of Bash where it's possible to pass multiple arrays by reference to a function...

我建议限制此类事情的单行使用,而是编写一个源代码到您的 shell 或脚本中的函数。这是较新版本的 Bash 的示例,其中可以通过引用函数来传递多个数组...

reverse_array(){
  local -n _source_array_ref=""
  local -n _destination_array_ref=""

  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

... however, with this technique do be aware that it makes a function that's impure(has side-effects), meaning that debugging _listor _new_listcan become difficult when in a Bash scripting mindset... also current examples don't take into account that one could re-run reverse_arrayand end up with _new_listappended to multiple times; which may or may not be desired.

...然而,使用这种技术时请注意,它会使函数不纯(有副作用),这意味着在 Bash 脚本思维中调试_list_new_list可能变得困难......而且当前的例子也没有考虑那个可以重新运行reverse_array并最终_new_list附加到多次;这可能是也可能不是需要的。

回答by M. Modugno

you can also consider using seq

你也可以考虑使用 seq

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

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

in freebsd you can omit -1 increment parameter:

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

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