Answers:
我已经按照书面回答了这个问题,并且这段代码反转了数组。(以相反顺序打印元素而不反转数组只是一个for
从最后一个元素向下计数到零的循环。)这是标准的“先交换后交换”算法。
array=(1 2 3 4 5 6 7)
min=0
max=$(( ${#array[@]} -1 ))
while [[ min -lt max ]]
do
# Swap current first and last elements
x="${array[$min]}"
array[$min]="${array[$max]}"
array[$max]="$x"
# Move closer
(( min++, max-- ))
done
echo "${array[@]}"
它适用于奇数和偶数长度的数组。
另一种非常规方法:
#!/bin/bash
array=(1 2 3 4 5 6 7)
f() { array=("${BASH_ARGV[@]}"); }
shopt -s extdebug
f "${array[@]}"
shopt -u extdebug
echo "${array[@]}"
输出:
7 6 5 4 3 2 1
如果extdebug
启用,则数组BASH_ARGV
在函数中以相反顺序包含所有位置参数。
非常规方法(都不都是纯方法bash
):
如果数组中的所有元素只是一个字符(如问题中所示),则可以使用rev
:
echo "${array[@]}" | rev
除此以外:
printf '%s\n' "${array[@]}" | tac | tr '\n' ' '; echo
并且如果可以使用zsh
:
echo ${(Oa)array}
tac
,cat
很容易记住,谢谢!
rev
,但我需要指出的是,rev
对于具有两位数的数字,它将无法正常工作。例如,12
使用rev 的数组元素将被打印为21
。试试看;-)
如果您实际上想要在另一个数组中反转:
reverse() {
# first argument is the array to reverse
# second is the output array
declare -n arr="$1" rev="$2"
for i in "${arr[@]}"
do
rev=("$i" "${rev[@]}")
done
}
然后:
array=(1 2 3 4)
reverse array foo
echo "${foo[@]}"
给出:
4 3 2 1
这应该正确处理缺少数组索引的情况,例如您有array=([1]=1 [2]=2 [4]=4)
,在这种情况下,从0循环到最高索引可能会添加其他空元素。
shellcheck
打印两个警告:array=(1 2 3 4)
<-- SC2034: array appears unused. Verify it or export it.
并且:echo "${foo[@]}"
<-- SC2154: foo is referenced but not assigned.
declare
行的用途。
declare -n
在4.3之前的bash版本中似乎不起作用。
要交换数组位置(即使是稀疏数组)(自bash 3.0起):
#!/bin/bash
# Declare an sparse array to test:
array=([5]=101 [6]=202 [10]=303 [11]=404 [20]=505 [21]=606 [40]=707)
echo "Initial array values"
declare -p array
swaparray(){ local temp; temp="${array[$1]}"
array[$1]="${array[$2]}"
array[$2]="$temp"
}
ind=("${!array[@]}") # non-sparse array of indexes.
min=-1; max="${#ind[@]}" # limits to one before real limits.
while [[ min++ -lt max-- ]] # move closer on each loop.
do
swaparray "${ind[min]}" "${ind[max]}" # Exchange first and last
done
echo "Final Array swapped in place"
declare -p array
echo "Final Array values"
echo "${array[@]}"
执行时:
./script
Initial array values
declare -a array=([5]="101" [6]="202" [10]="303" [11]="404" [20]="505" [21]="606" [40]="707")
Final Array swapped in place
declare -a array=([5]="707" [6]="606" [10]="505" [11]="404" [20]="303" [21]="202" [40]="101")
Final Array values
707 606 505 404 303 202 101
对于较旧的bash,您需要使用循环(在bash中(自2.04起)),并使用$a
以避免循环空间:
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a=""
for (( i=last-1 ; i>=0 ; i-- ));do
printf '%s%s' "$a" "${array[i]}"
a=" "
done
echo
对于自2.03起的bash:
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a="";i=0
while [[ last -ge $((i+=1)) ]]; do
printf '%s%s' "$a" "${array[ last-i ]}"
a=" "
done
echo
另外(使用按位求反运算符)(自bash 4.2+起):
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a=""
for (( i=0 ; i<last ; i++ )); do
printf '%s%s' "$a" "${array[~i]}"
a=" "
done
echo
丑陋,难以维护,但单线:
eval eval echo "'\"\${array['{$((${#array[@]}-1))..0}']}\"'"
eval eval echo "'\"\${array[-'{1..${#array[@]}}']}\"'"
。
ind=("${!array[@]}");eval eval echo "'\"\${array[ind[-'{1..${#array[@]}}']]}\"'"
虽然我不会讲新的东西,也将tac
用于反转数组,但是我值得一提的是使用bash 4.4版的波纹管单行解决方案:
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}" |tac)
测试:
$ array=(1 2 3 4 5 6 10 11 12)
$ echo "${array[@]}"
1 2 3 4 5 6 10 11 12
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}"|tac)
$ echo "${array[@]}"
12 11 10 6 5 4 3 2 1
请注意,读取中的var名称是作为原始数组的名称,因此临时存储不需要辅助数组。
通过调整IFS的替代实现:
$ IFS=$'\n' read -d '' -a array < <(printf '%s\n' "${array[@]}"|tac);declare -p array
declare -a array=([0]="12" [1]="11" [2]="10" [3]="6" [4]="5" [5]="4" [6]="3" [7]="2" [8]="1")
PS:由于不同的bash内置函数实现,我认为上述解决方案在bash
波纹管版本中不起作用。4.4
read
IFS
版本有效,但也可以打印:declare -a array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="10" [7]="11" [8]="12")
。使用bash 4.4-5
。您必须;declare -p array
在第一行的末尾将其删除,然后才能正常工作……
declare -p
是使bash打印实际数组(索引和内容)的一种快速方法。您不需要declare -p
在实际脚本中使用此命令。如果在数组分配中出了点问题,您可能会遇到${array[0]}="1 2 3 4 5 6 10 11 12"
=所有值都存储在同一索引中的情况-使用echo,您将看不到任何区别。对于快速数组打印,使用declare -p array
将返回实际数组索引以及每个索引中的对应值。
read -d'\n'
方法对您不起作用?
read -d'\n'
工作良好。
反转任意数组(可以包含任意数量的带有任何值的元素):
与zsh
:
array_reversed=("${(@Oa)array}")
在bash
4.4+版本中,假设bash
变量无论如何都不能包含NUL字节,则可以tac -s ''
在以NUL分隔记录打印的元素上使用GNU :
readarray -td '' array_reversed < <(
((${#array[@]})) && printf '%s\0' "${array[@]}" | tac -s '')
POSIXly,扭转POSIX壳阵列($@
,制成$1
,$2
...):
code='set --'
n=$#
while [ "$n" -gt 0 ]; do
code="$code \"\${$n}\""
n=$((n - 1))
done
eval "$code"
纯bash解决方案可以单线工作。
$: for (( i=${#array[@]}-1; i>=0; i-- ))
> do rev[${#rev[@]}]=${array[i]}
> done
$: echo "${rev[@]}"
7 6 5 4 3 2 1
rev+=( "${array[i]}" )
似乎更简单。
array=(1 2 3 4 5 6 7)
echo "${array[@]} " | tac -s ' '
要么
array=(1 2 3 4 5 6 7)
reverse=$(echo "${array[@]} " | tac -s ' ')
echo ${reverse[@]}
7 6 5 4 3 2 1
$ tac --version
tac (GNU coreutils) 8.28