Yanıtlar:
Soruyu yazılı olarak yanıtladım ve bu kod diziyi tersine çevirir. (Diziyi tersine çevirmeden öğeleri ters sırada yazdırmak, yalnızca for
son öğeden sıfıra geri sayım yapan bir döngüdür.) Bu standart bir "ilk ve son değiştirme" algoritmasıdır.
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[@]}"
Tek ve eşit uzunlukta diziler için çalışır.
Başka bir alışılmadık yaklaşım:
#!/bin/bash
array=(1 2 3 4 5 6 7)
f() { array=("${BASH_ARGV[@]}"); }
shopt -s extdebug
f "${array[@]}"
shopt -u extdebug
echo "${array[@]}"
Çıktı:
7 6 5 4 3 2 1
Eğer extdebug
etkinleştirildiğinde, dizi BASH_ARGV
ters sırada tüm konumsal parametreler işlevde içerir.
Alışılmadık yaklaşım (hepsi saf değil bash
):
bir dizideki tüm öğeler yalnızca bir karakterse (sorudaki gibi) kullanabilirsiniz rev
:
echo "${array[@]}" | rev
aksi takdirde:
printf '%s\n' "${array[@]}" | tac | tr '\n' ' '; echo
ve eğer kullanabiliyorsanız zsh
:
echo ${(Oa)array}
tac
tersi olarak, cat
, TEŞEKKÜRLER hatırlamak oldukça iyi!
rev
bahsetmek gerekir rev
. Örneğin 12
rev kullanımının bir dizi öğesi olarak yazdırılacaktır 21
. Bir deneyin ;-)
Aslında tersi başka bir dizide istiyorsanız:
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
}
Sonra:
array=(1 2 3 4)
reverse array foo
echo "${foo[@]}"
verir:
4 3 2 1
Bu, bir dizi dizininin eksik olduğu durumları, örneğin array=([1]=1 [2]=2 [4]=4)
0'dan en yüksek dizine döngü yapmak ek, boş, elemanlar ekleyebilir.
shellcheck
iki uyarı yazdırıyor: array=(1 2 3 4)
<-- SC2034: array appears unused. Verify it or export it.
ve bunun için:echo "${foo[@]}"
<-- SC2154: foo is referenced but not assigned.
declare
hat bunun için.
declare -n
4.3'ten önceki bash sürümlerinde işe yaramadığını unutmayın .
Dizi konumlarını yerinde değiştirmek için (seyrek dizilerle bile) (bash 3.0'dan beri):
#!/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[@]}"
Yürütme sırasında:
./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
Eski bash için, bir döngü (bash (2.04'ten beri)) kullanmanız $a
ve arka boşluktan kaçınmak için kullanmanız gerekir:
#!/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'ten beri bash için:
#!/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
Ayrıca (bitsel olumsuzlama operatörünü kullanarak) (bash 4.2+'den beri):
#!/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
Çirkin, sürdürülemez, ancak bir astar:
eval eval echo "'\"\${array['{$((${#array[@]}-1))..0}']}\"'"
eval eval echo "'\"\${array[-'{1..${#array[@]}}']}\"'"
.
ind=("${!array[@]}");eval eval echo "'\"\${array[ind[-'{1..${#array[@]}}']]}\"'"
Yeni bir şey anlatmayacağım ve ben de tac
diziyi tersine çevirmek için kullanacak olsa da, ben bash 4.4 sürümünü kullanarak feryat tek satır çözüm bahsetmeye layık olsa da:
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}" |tac)
Test yapmak:
$ 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
Okuma içindeki var adının orijinal dizi olarak ad olduğunu unutmayın, bu nedenle geçici depolama için yardımcı dizi gerekmez.
IFS'yi ayarlayarak alternatif uygulama:
$ 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")
Not: Yukarıdaki çözümlerin farklı bash yerleşik işlev uygulaması nedeniyle bash
feryat versiyonunda çalışmayacağını düşünüyorum .4.4
read
IFS
Versiyon çalışıyor ama o da yazdırıyor: declare -a array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="10" [7]="11" [8]="12")
. Bash kullanma 4.4-5
. ;declare -p array
İlk satırın sonunda kaldırmanız gerekiyor , o zaman işe yarıyor ...
declare -p
, bash baskısını gerçek dizi (dizin ve içerik) yapmanın hızlı bir yoludur. declare -p
Gerçek komut dosyanızda bu komuta ihtiyacınız yoktur . Dizilerinizin atamalarında bir şeyler ters giderse ${array[0]}="1 2 3 4 5 6 10 11 12"
, aynı dizinde depolanan tüm değerlerin = yankı kullanarak bir fark görmeyeceksiniz. Hızlı bir dizi çıktısı için declare -p array
, kullanarak gerçek dizi indeksleri ve her dizindeki karşılık gelen değer döndürülür.
read -d'\n'
yöntem sizin için işe yaramadı mı?
read -d'\n'
iyi çalışıyor.
Rasgele bir diziyi tersine çevirmek için (herhangi bir değere sahip çok sayıda öğe içerebilir):
İle zsh
:
array_reversed=("${(@Oa)array}")
İle bash
4.4+, göz önüne alındığında bash
değişkenler GNU'yu kullanabilirsiniz, NUL zaten bayt içeremez tac -s ''
NUL kayıtlarını ayrılmış olarak basılmış elemanlarında:
readarray -td '' array_reversed < <(
((${#array[@]})) && printf '%s\0' "${array[@]}" | tac -s '')
POSIXly, POSIX kabuk dizisini tersine çevirmek için ( $@
, yapılmış $1
, $2
...):
code='set --'
n=$#
while [ "$n" -gt 0 ]; do
code="$code \"\${$n}\""
n=$((n - 1))
done
eval "$code"
Saf bash çözümü, tek astar olarak çalışır.
$: 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]}" )
daha basit görünüyor.
ayrıca kullanmayı düşünebilirsiniz seq
array=(1 2 3 4 5 6 7)
for i in $(seq $((${#array[@]} - 1)) -1 0); do
echo ${array[$i]}
done
freebsd'de -1 artış parametresini atlayabilirsiniz:
for i in $(seq $((${#array[@]} - 1)) 0); do
echo ${array[$i]}
done
array=(1 2 3 4 5 6 7)
echo "${array[@]} " | tac -s ' '
Veya
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
tac
zaten belirtilmişti: unix.stackexchange.com/a/412874/260978 , unix.stackexchange.com/a/467924/260978 , unix.stackexchange.com/a/413176/260978