回答:
質問に書かれたとおりに答えましたが、このコードは配列を逆にします。(配列を逆にせずに要素を逆順に印刷することは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[@]}"
奇数と偶数の長さの配列に対して機能します。
型破りなアプローチ(すべて純粋ではありませんbash
):
配列内のすべての要素が1文字だけの場合(質問のように)、次を使用できます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
2つの警告が出力されますが、これは非常にうまく機能します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
glyい、維持できないが、ワンライナー:
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
read内の変数名は元の配列の名前であるため、一時ストレージにヘルパー配列は必要ありません。
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"
=すべての値が同じインデックスに格納されている場合があります。エコーを使用すると、違いは見られません。を使用して配列をすばやく印刷するにdeclare -p array
は、実際の配列インデックスと各インデックスの対応する値を返します。
read -d'\n'
方法はうまくいきませんでしたか?
read -d'\n'
正常に動作します。
任意の配列(任意の値を持つ任意の数の要素を含む可能性がある)を反転するには:
でzsh
:
array_reversed=("${(@Oa)array}")
ではbash
4.4以降、ことを考えるとbash
変数がNULはとにかくバイトを含めることはできません、あなたはGNUを使用することができますtac -s ''
NULがレコードを区切りとして、印刷された要素に:
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]}" )
は簡単に思えます。
また、使用を検討することができます seq
array=(1 2 3 4 5 6 7)
for i in $(seq $((${#array[@]} - 1)) -1 0); do
echo ${array[$i]}
done
freebsdでは、-1増分パラメーターを省略できます。
for i in $(seq $((${#array[@]} - 1)) 0); do
echo ${array[$i]}
done
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