มีวิธีง่าย ๆ ในการย้อนกลับอาร์เรย์หรือไม่
#!/bin/bash
array=(1 2 3 4 5 6 7)
echo "${array[@]}"
ดังนั้นฉันจะได้รับ: 7 6 5 4 3 2 1
แทน:1 2 3 4 5 6 7
มีวิธีง่าย ๆ ในการย้อนกลับอาร์เรย์หรือไม่
#!/bin/bash
array=(1 2 3 4 5 6 7)
echo "${array[@]}"
ดังนั้นฉันจะได้รับ: 7 6 5 4 3 2 1
แทน:1 2 3 4 5 6 7
คำตอบ:
ฉันได้ตอบคำถามตามที่เขียนไว้และรหัสนี้จะกลับรายการอาร์เรย์ (การพิมพ์องค์ประกอบในลำดับย้อนกลับโดยไม่ต้องย้อนกลับอาร์เรย์เป็นเพียงการ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
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 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
สำหรับ bash ตั้งแต่ 2.03:
#!/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
นอกจากนี้ (ใช้ตัวดำเนินการปฏิเสธบิต) (ตั้งแต่ทุบตี 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
เวอร์ชันร้อง4.4
เนื่องจากread
การใช้ฟังก์ชั่น bash builtin ที่แตกต่างกัน
IFS
รุ่นทำงาน declare -a array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="10" [7]="11" [8]="12")
แต่ก็ยังพิมพ์: 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 ไบต์ได้คุณสามารถใช้ 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"
วิธีทุบตีบริสุทธิ์จะทำงานเป็นหนึ่งซับ
$: 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