มีวิธีอ่านองค์ประกอบสุดท้ายของอาร์เรย์ที่มี bash หรือไม่?


68

ถ้าฉันมีอาร์เรย์ที่มี 5 องค์ประกอบตัวอย่างเช่น:

[a][b][c][d][e]

ใช้echo ${myarray[4]}ฉันสามารถดูสิ่งที่มันถือ

แต่ถ้าฉันไม่ทราบจำนวนองค์ประกอบในอาร์เรย์ที่กำหนดล่ะ มีวิธีอ่านองค์ประกอบสุดท้ายของอาร์เรย์ความยาวที่ไม่รู้จักหรือไม่? เช่นองค์ประกอบแรกอ่านจากขวาไปซ้ายสำหรับอาร์เรย์ใด ๆ

ฉันต้องการทราบวิธีการทำเช่นนี้ในทุบตี


$@ไม่ใช่อาร์เรย์ (ไม่สามารถห้อยได้) มันเห็นการโต้แย้งที่ผ่านมาส่งผ่านไปยังสคริปต์เปลือก
Tom Hale

คำตอบ:


89

คุณสามารถใช้ดัชนีลบ ${myarray[-1]}เพื่อรับองค์ประกอบสุดท้าย คุณสามารถทำสิ่งเดียวกันสำหรับครั้งที่สองและอื่น ๆ ; ใน Bash:

หากตัวห้อยที่ใช้ในการอ้างอิงองค์ประกอบของอาเรย์ที่จัดทำดัชนีประเมินจำนวนน้อยกว่าศูนย์มันจะถูกตีความว่าสัมพันธ์กับหนึ่งที่สูงกว่าดัชนีสูงสุดของอาเรย์ดังนั้นดัชนีเชิงลบนับถอยหลังจากจุดสิ้นสุดของอาเรย์และ ดัชนี -1 หมายถึงองค์ประกอบสุดท้าย

เช่นเดียวกับการทำงานที่ได้รับมอบหมาย เมื่อมันบอกว่า "expression" มันหมายถึงการแสดงออกจริงๆ; คุณสามารถเขียนในนิพจน์ทางคณิตศาสตร์ใด ๆ ที่นั่นเพื่อคำนวณดัชนีรวมถึงสิ่งที่คำนวณโดยใช้ความยาวของอาร์เรย์${#myarray[@]}อย่างชัดเจน


2
คุณสามารถทำเช่นนั้นในkshและzshเช่นกัน
Janis

5
ด้วยzshแม้ว่าโดยค่าเริ่มต้นอาร์เรย์จะมีการจัดทำดัชนี 1 ซึ่งแตกต่างbashและkshที่พวกเขาจะถูกจัดทำดัชนี 0
สตีเฟ่น Kitt

2
ใช่แน่นอน คำตอบสั้น ๆ สำหรับคำถามนี้ไม่เปลี่ยน แต่เนื่องจากมีการพูดถึงแบบยาวฉันคิดว่ามันจำเป็นที่จะต้องชี้ให้เห็นถึงความแตกต่างในพฤติกรรมที่นั่น
Stephen Kitt

22
ดัชนีเชิงลบใช้งานได้ในทุบตี 4.3 ขึ้นไป
cuonglm

10
เวอร์ชั่นของ Bash ที่มาพร้อมกับ Mac OS X อย่างน้อย v10.11.5 นั้นมีเพียง 3.2 ดังนั้นจึงไม่สามารถใช้งานบน Mac ได้
Doktor J

45

Modern bash (v4.1 หรือดีกว่า)

คุณสามารถอ่านองค์ประกอบสุดท้ายที่ดัชนี-1:

$ a=(a b c d e f)
$ echo ${a[-1]}
f

การสนับสนุนสำหรับการเข้าถึงอาร์เรย์ตัวเลขการจัดทำดัชนีจากสิ้นโดยใช้ดัชนีเชิงลบเริ่มต้นด้วยการทุบตีรุ่น 4.1

bash รุ่นเก่ากว่า (v4.0 หรือเก่ากว่า)

คุณต้องรับความยาวของอาเรย์${#a[@]}แล้วจึงลบออกหนึ่งอันเพื่อให้ได้องค์ประกอบสุดท้าย

$ echo ${a[${#a[@]}-1]}
f

เนื่องจาก bash ใช้ตัวห้อยอาร์เรย์เป็นนิพจน์ทางคณิตศาสตร์จึงไม่จำเป็นต้องมีเครื่องหมายเพิ่มเติมเช่น$((...))เพื่อบังคับให้มีการประเมินทางคณิตศาสตร์


อันสุดท้ายไม่ได้ผลสำหรับฉัน; ฉันใช้ Bash v4.1.2 (1): แทนที่จะพิมพ์รายการสุดท้ายมันแค่พิมพ์อาร์เรย์ทั้งหมด
Alexej Magura

อย่างไรก็ตามคำตอบของ @ cuonglm ใช้ได้ผล
Alexej Magura

คำตอบจะดียิ่งขึ้นหากคุณมีสิทธิ์ได้รับmodernเวอร์ชัน
Samveen

1
สิ่งที่จำเป็นในการทำให้ผู้ตอบสมบูรณ์
Samveen

1
ขอบคุณสำหรับสิ่งนี้. ฉันใช้ echo $ {a [$ (($ {# a [@]} - 1]))}} เพราะฉันไม่รู้เกี่ยวกับ "bash ถือว่าตัวห้อยอาร์เรย์เป็นนิพจน์ทางคณิตศาสตร์"
Bruno Bronosky

15

bashการกำหนดอาร์เรย์การอ้างอิงการไม่ตั้งค่าด้วยดัชนีลบจะถูกเพิ่มในทุบตี 4.3เท่านั้น ด้วยเวอร์ชันที่เก่ากว่าของbashคุณสามารถใช้การแสดงออกในดัชนีarray[${#array[@]-1}]

อีกวิธีหนึ่งทำงานร่วมกับเวอร์ชันเก่ากว่าbash(bash 3.0 หรือดีกว่า):

$ a=([a] [b] [c] [d] [e])
$ printf %s\\n "${a[@]:(-1)}"
[e]

หรือ:

$ printf %s\\n "${a[@]: -1}"
[e]

การใช้ออฟเซ็ตเชิงลบคุณต้องแยก:ด้วย-เพื่อหลีกเลี่ยงการสับสนกับการ:-ขยาย


1
ให้ที่"${a[@]: -1}"และมันจะทำงาน (นอกเหนือจากbashและzsh) kshยังอยู่ใน
Janis

เอกสาร Kornshell ( www2.research.att.com/sw/download/man/man1/ksh.html ) ระบุไว้โดยสมบูรณ์ (ยังไม่ได้ตรวจสอบเอกสารของzshหรือbashแต่ผมทดสอบในทั้งสามหอย.)
เจนิส

@ Janis: อ่านเอกสารทุบตีอีกครั้งมันยังพูดถึงเรื่องนี้ด้วย ขอบคุณอีกครั้ง.
cuonglm

4

แถว

ตัวเลือกที่เก่าแก่ที่สุดใน bash (ตั้งแต่ bash 3.0+) คือ:

$ a=(aa bb cc dd ee)
$ echo "${a[@]:(-1)}   ${a[@]: -1}   ${a[@]:(~0)}   ${a[@]:~0}"
ee   ee   ee   ee

จำเป็นต้องใช้พื้นที่เพื่อหลีกเลี่ยงการตีความ:ตามด้วยเครื่องหมายลบ-เป็นการขยาย"${var:-abc}"(ใช้ค่าเริ่มต้น)

นี่~คือการปฏิเสธแบบเลขคณิตในเลขคณิต(เทียบเท่ากับส่วนเติมเต็มหรือพลิกทุกบิต ) จากคนทุบตี:

การประเมินผลทางคณิตศาสตร์

      ! ~         logical and bitwise negation  

ตั้งแต่ bash-4.2 + ด้วย:

$ echo "${a[-1]}   ${a[(~0)]}"
ee   ee

ตั้งแต่ทุบตี 5.0+ ด้วย:

$ echo "${a[~0]}"
ee

สำหรับทุกรุ่นทุบตี (ทุบตีเก่ากว่า):

$ echo "${a[   ${#a[@]}-1   ]}"    # spaces added **only** for readability
ee

แอท

สำหรับอาร์กิวเมนต์ตำแหน่ง (ตั้งแต่ bash 2.01):

$ set aa bb cc dd ee
$ echo "${@:(-1)} ${@:~0} ${@: -1} ${@:$#}   ${!#}"
ee ee ee   ee

โซลูชันแบบพกพาสำหรับเชลล์ทั้งหมดคือการใช้ eval:

eval printf '"%s\n"' \"\${$#}\"

คุณมีการอ้างอิงสำหรับ bash 5+ หรือไม่ ฉันค้นหาอินสแตนซ์ทั้งหมด 58 รายการ~ในคู่มือและไม่เห็น
Tom Hale

... และคุณจะทำอย่างไรกับ$@? bash: ${@[@]:(-1)}: bad substitution
Tom Hale

1
ใช่มีการman bashอ้างอิง (ตรวจสอบคำตอบเพิ่มเติมที่ @ ชื่อเรื่อง) @TomHale
Isaac

1
@คือไม่อาร์เรย์ (ดีไม่เต็มที่อาร์เรย์ ) ในทุบตีและจะไม่ยอมรับดัชนี ( []) ห้อยสำหรับข้อโต้แย้งของแต่ละบุคคล คุณจำเป็นต้องใช้${@:(-1)}หรือเทียบเท่า ตรวจสอบรายการที่ถูกขยายที่@ชื่อ @TomHale
Isaac

-2

นอกจากนี้คุณสามารถทำสิ่งนี้:

$ a=(a b c d e f)
$ echo ${a[$(expr ${#a[@]} - 1)]}

ผลลัพธ์:

$ f

สิ่งที่คุณทำคือรับจำนวนองค์ประกอบทั้งหมดในอาร์เรย์และลบ -1 เนื่องจากคุณได้รับองค์ประกอบทั้งหมดไม่ใช่เริ่มต้นจากดัชนีอาร์เรย์นั่นคือ 0

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