ฉันจะเปลี่ยน bash array ที่ดัชนีบางตัวที่อยู่ตรงกลางได้อย่างไร


12
1  #!/bin/bash
2  # query2.sh
3
4  numbers=(53 8 12 9 784 69 8 7 1)
5  i=4
6
7  echo ${numbers[@]} # <--- this echoes "53 8 12 9 784 69 8 7 1" to stdout.
8  echo ${numbers[i]} # <--- this echoes "784" to stdout.
9
10 unset numbers[i]
11
12 echo ${numbers[@]} # <--- this echoes "53 8 12 9 69 8 7 1" to stdout.
13 echo ${numbers[i]} # <--- stdout is blank.

เหตุใดในบรรทัดที่ 13 stdout จึงว่างเปล่าเมื่อพิจารณาว่าอาร์เรย์ดูเหมือนว่าได้รับการอัปเดตการตัดสินโดย stdout ของบรรทัดที่ 12

แล้วฉันควรทำอย่างไรเพื่อให้ได้คำตอบที่ต้องการ "69"


1
เมื่อพิจารณาถึงประเภทของการเข้ารหัสที่คำถามนี้บ่งบอกคุณควรระวัง: ดูมีบางอย่างผิดปกติกับสคริปต์ของฉันหรือ Bash ช้ากว่า Python มากหรือไม่?
Wildcard

คำตอบ:


21

unsetลบองค์ประกอบ มันไม่เปลี่ยนเลของค์ประกอบที่เหลือ

เราสามารถใช้declare -pเพื่อดูว่าเกิดอะไรขึ้นกับnumbers:

$ unset "numbers[i]"
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")

สังเกตไม่ได้มีองค์ประกอบnumbers4

ตัวอย่างอื่น

สังเกต:

$ a=()
$ a[1]="element 1"
$ a[22]="element 22"
$ declare -p a
declare -a a=([1]="element 1" [22]="element 22")

Array aไม่มีองค์ประกอบ 2 ถึง 21 Bash ไม่ต้องการให้ดัชนีอาร์เรย์เรียงติดกัน

วิธีที่แนะนำในการบังคับให้ทำการจัดลำดับดัชนีใหม่

เริ่มต้นด้วยnumbersอาร์เรย์ด้วยองค์ประกอบที่ขาดหายไป4:

$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")

หากเราต้องการให้ดัชนีมีการเปลี่ยนแปลงให้ทำดังนี้:

$ numbers=("${numbers[@]}")
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [4]="69" [5]="8" [6]="7" [7]="1")

ขณะนี้มีจำนวนองค์ประกอบและมันมีค่า469

วิธีอื่นในการลบองค์ประกอบ & เปลี่ยนลำดับหมายเลขในขั้นตอนเดียว

อีกครั้งให้คำจำกัดความnumbers:

$ numbers=(53 8 12 9 784 69 8 7 1)

ตามที่Toby Speight แนะนำในความคิดเห็นวิธีการลบองค์ประกอบที่สี่และกำหนดหมายเลของค์ประกอบที่เหลือทั้งหมดใหม่ในขั้นตอนเดียว:

$ numbers=("${numbers[@]:0:4}" "${numbers[@]:5}")
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [4]="69" [5]="8" [6]="7" [7]="1")

อย่างที่คุณเห็นองค์ประกอบที่สี่ถูกลบและองค์ประกอบที่เหลือทั้งหมดถูกจัดลำดับใหม่

${numbers[@]:0:4}อาร์เรย์ slices numbers: ใช้องค์ประกอบสี่รายการแรกที่เริ่มต้นด้วยองค์ประกอบ 0

ในทำนองเดียวกัน${numbers[@]:5}array slice numbers: จะใช้องค์ประกอบทั้งหมดที่เริ่มต้นด้วยองค์ประกอบที่ 5 และดำเนินการต่อจนถึงจุดสิ้นสุดของอาร์เรย์

การรับดัชนีของอาร์เรย์

ค่า${a[@]}ของอาร์เรย์สามารถรับกับ เพื่อหาดัชนี (หรือปุ่ม ) ${!a[@]}ที่สอดคล้องกับค่าเหล่านั้นใช้

ตัวอย่างเช่นลองพิจารณาอาร์เรย์ของเราอีกครั้งnumbersด้วยองค์ประกอบที่ขาดหายไป4:

$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")

หากต้องการดูดัชนีที่ได้รับมอบหมาย:

$ echo "${!numbers[@]}"
0 1 2 3 5 6 7 8

อีกครั้ง4หายไปจากรายการดัชนี

เอกสาร

จากman bash:

unsetbuiltin จะใช้ในการทำลายอาร์เรย์ ทำลายองค์ประกอบอาร์เรย์ที่ดัชนีunset name[subscript] subscriptตัวห้อยเชิงลบไปยังอาร์เรย์ที่จัดทำดัชนีจะถูกตีความตามที่อธิบายไว้ข้างต้น ต้องใช้ความระมัดระวังเพื่อหลีกเลี่ยงผลข้างเคียงที่ไม่พึงประสงค์ที่เกิดจากการขยายชื่อพา ธ unset nameที่nameเป็นอาร์เรย์หรือunset name[subscript]ที่subscriptเป็น * หรือ @เอาอาร์เรย์ทั้งหมด


1
โปรดทราบว่าไวยากรณ์ของเชลล์อาเรย์เป็นวิธีการที่จะทำให้ง่ายต่อการจัดการกับตัวแปรที่มีชื่อคล้ายกัน ไม่มีเป็นอาร์เรย์ตัวเอง; ในความเป็นจริงหลังจากที่คุณเขียนa=()ตัวแปรaจะยังไม่ได้กำหนดจนกว่าคุณจะกำหนดให้กับหนึ่งในดัชนี
chepner

@ John1024: ขอบคุณสำหรับคำตอบนี้ คุณอาจจะขยายมันเพื่อรวมคำตอบที่แนะนำเพื่อให้ได้ผลลัพธ์ที่ต้องการ
Anthony Webber

@AnthonyWebber แน่นอน ฉันเพิ่มส่วนหนึ่งในคำตอบเพื่อแสดงวิธีบังคับให้จัดเรียงดัชนีใหม่
John1024

2
เพียงแค่พูดถึงวิธีการทางเลือกอื่น (ซึ่งอาจเหมาะกับบางโค้ด): แทนที่จะunset numbers[4]กำหนดทั้งอาร์เรย์โดยใช้การแบ่งส่วนnumbers=("${numbers[@]:0:4}" "${numbers[@]:5}")(ฉันจะโพสต์เป็นคำตอบ แต่ไม่มีเวลาอธิบายอย่างถูกต้อง)
Toby Speight

@ John1024: ขอบคุณที่คุณทำเช่นนั้น และขอบคุณ Toby :)
Anthony Webber

5

bashArray in in kshไม่ใช่อาร์เรย์จริงๆพวกมันเหมือน Array Array ที่มีคีย์ จำกัด จำนวนเต็มบวก (หรือที่เรียกว่าSparse Array ) สำหรับเปลือกกับอาร์เรย์จริงที่คุณสามารถดูได้ที่หอยชอบrc, es, fish, yash, zsh(หรือแม้กระทั่งcsh/ tcshแม้ว่าหอยเหล่านั้นมีปัญหาหลายอย่างเพื่อให้พวกเขากำลังหลีกเลี่ยงดีกว่า)

ในzsh:

a=(1 2 3 4 5)
a[3]=() # remove the 3rd element
a[1,3]=() # remove the first 3 elements
a[-1]=() # remove the last element

(โปรดทราบว่าใน zsh unset 'a[3]'จริง ๆ แล้วตั้งเป็นสตริงว่างเปล่าเพื่อปรับปรุงความเข้ากันได้กับksh)

ในyash:

a=(1 2 3 4 5)
array -d a 3 # remove the 3rd element
array -d a 1 2 3 # remove the first 3 elements
array -d a -1 # remove the last element

ในfish(ไม่ใช่เชลล์คล้ายบอร์นตรงกันข้ามกับbash/ zsh):

set a 1 2 3 4 5
set -e a[3] # remove the 3rd element
set -e a[1..3] # remove the first 3 elements
set -e a[-1] # remove the last element

ในes(ตามrcไม่ใช่บอร์นเหมือน)

a = 1 2 3 4 5
a = $a(... 2 4 ...) # remove the 3rd element
a = $a(4 ...) # remove the first 3 elements
a = $a(... `{expr $#a - 1}) # remove the last element
# or a convoluted way that avoids forking expr:
a = $a(... <={@{*=$*(2 ...); return $#*} $a})

ในkshและbash

คุณสามารถใช้อาร์เรย์เป็นอาร์เรย์ปกติได้หากคุณ:

a=("${a[@]}")

หลังจากการดำเนินการลบหรือแทรกแต่ละครั้งที่อาจทำให้รายการของดัชนีไม่ต่อเนื่องกันหรือไม่เริ่มที่ 0 นอกจากนี้โปรดทราบว่าksh/ bashอาร์เรย์เริ่มต้นที่ 0 ไม่ใช่ 1 (ยกเว้น$@(ในบางวิธี))

ที่จะมีผลเป็นระเบียบเรียบร้อยองค์ประกอบและย้ายไปยังดัชนี 0, 1, 2 ... ตามลำดับ

โปรดทราบด้วยว่าคุณต้องอ้างถึงnumber[i]ใน:

unset 'number[i]'

มิฉะนั้นจะถือว่าเป็นเช่นunset numberiนั้นมีไฟล์ที่เรียกว่าnumberiในไดเรกทอรีปัจจุบัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.