โครงสร้างข้อมูลของ $ @ ในเชลล์คืออะไร?


13

เรามักจะใช้$@เพื่อเป็นตัวแทนของการโต้แย้งทั้งหมดยกเว้น $ 0 อย่างไรก็ตามฉันไม่รู้ว่าโครงสร้างข้อมูล$@คืออะไร

ทำไมมันมีพฤติกรรมแตกต่างกัน$*เมื่อรวมอยู่ในเครื่องหมายคำพูดคู่ใครสามารถให้คำอธิบายระดับล่ามให้ฉันได้หรือไม่

มันสามารถวนซ้ำในห่วงดังนั้นดูเหมือนว่าจะเป็นอาร์เรย์ อย่างไรก็ตามมันยังสามารถสะท้อนได้อย่างง่ายดายecho $@ถ้าเป็นอาร์เรย์จะมีเพียงองค์ประกอบแรกเท่านั้นที่แสดง เนื่องจากข้อ จำกัด ของเชลล์ฉันไม่สามารถเขียนโค้ดการทดสอบเพิ่มเติมเพื่อดำเนินการได้

ความแตกต่างระหว่างโพสต์นี้ : โพสต์นี้แสดงให้เห็นว่า$@พฤติกรรมแตกต่างจาก$*อย่างไร $@แต่ฉันสงสัยเกี่ยวกับชนิดข้อมูลของ เชลล์ในฐานะภาษาตีความเช่น Python ควรแสดงข้อมูลตามชุดของประเภทพื้นฐาน หรือกล่าวอีกนัยหนึ่งฉันต้องการทราบว่า $ @ เก็บไว้ในหน่วยความจำคอมพิวเตอร์อย่างไร

มันเป็นสตริงสตริงหลายบรรทัดหรืออาร์เรย์หรือไม่?

หากเป็นชนิดข้อมูลที่ไม่ซ้ำใครเป็นไปได้ไหมที่จะกำหนดตัวแปรที่กำหนดเองเป็นตัวอย่างของประเภทนี้


1
สำเนาที่เป็น
Haxiel

@Haxiel ฉันไม่คิดอย่างนั้นฉันเขียนความแตกต่างที่ด้านล่างของโพสต์
davmos

คุณจะได้รับการบริการที่ดีขึ้นโดยการทดสอบความแตกต่างในการส่งออกด้วยและprintf '%s\n' "$@" ยูทิลิตี้เพียง outputs อาร์กิวเมนต์ไม่ว่าหากพวกเขาเป็นคนหนึ่งหรือหลายคน ทั้งสองเป็นอาร์เรย์ (ของสตริง) แต่จะทำงานแตกต่างกันเมื่อยกมาสองครั้ง หากเป็นสตริงหลายบรรทัดก็จะไม่สามารถเก็บสตริงหลายบรรทัดได้ ยังไม่ชัดเจนว่าคุณพยายามแก้ไขปัญหาอะไร printf '%s\n' "$*"echo
Kusalananda

2
คำถามของคุณเทียบเท่ากับการถามว่า@varตัวแปรคืออะไรใน Perl ในแง่ของการจัดเก็บข้อมูลพื้นฐาน จากมุมมองของโปรแกรม Perl ธรรมดามันไม่สำคัญอะไรนอกจากนั้นมันสามารถเข้าถึงได้ในฐานะอาร์เรย์ / รายการ (และความจริงที่ว่ามีบริบทที่คาดว่าจะมีรายการ)
Kusalananda

คำตอบ:


16

นั่นเริ่มต้นเป็นแฮ็คในเชลล์เป้าหมาย ในเชลล์เป้าหมายการแยกคำ IFS เสร็จแล้ว (หลังจาก tokenisation) กับทุกคำในบริบทรายการ (อาร์กิวเมนต์บรรทัดคำสั่งหรือคำที่forลูปวนบน) ถ้าคุณมี:

IFS=i var=file2.txt
edit file.txt $var

ที่บรรทัดที่สองจะ tokenised ใน 3 คำ$varจะขยายและแยก + glob จะทำในทุกสามคำดังนั้นคุณจะสิ้นสุดการทำงานedกับt, f, le.txt, f, le2.txtเป็นข้อโต้แย้ง

การอ้างถึงบางส่วนของสิ่งนั้นจะป้องกัน + + glob แยก เชลล์เป้าหมายในขั้นต้นจำได้ว่าอักขระตัวใดที่อ้างถึงโดยตั้งค่าบิตที่ 8 ไว้ภายใน (ซึ่งเปลี่ยนในภายหลังเมื่อ Unix กลายเป็น 8 บิตที่สะอาด

ทั้งสอง$*และ$@เป็นการต่อกันของพารามิเตอร์ตำแหน่งกับช่องว่างระหว่าง แต่มีการประมวลผลพิเศษ$@เมื่ออยู่ในเครื่องหมายคำพูดคู่ หาก$1มีfoo barและ$2มีอยู่baz, "$@"จะขยายไปยัง:

foo bar baz
^^^^^^^ ^^^

(ด้วย^s ด้านบนแสดงว่าอักขระตัวใดมีชุดบิตที่ 8) โดยที่ช่องว่างแรกถูกยกมา (มีชุดบิตที่ 8) แต่ไม่ใช่ช่องว่างที่สอง (อันที่เพิ่มเข้ามาระหว่างคำ)

และมันคือการแยก IFS ที่ดูแลการแยกอาร์กิวเมนต์ (สมมติว่าอักขระช่องว่างอยู่ใน$IFSตามที่เป็นค่าเริ่มต้น) นั่นคล้ายกับวิธีการ$*ขยายในรุ่นก่อนหน้าของเปลือก Mashey (ตัวเองขึ้นอยู่กับเปลือก Thomson ในขณะที่เชลล์เป้าหมายถูกเขียนขึ้นจากรอยขีดข่วน)

ที่อธิบายว่าทำไมในบอร์นเปลือกแรก"$@"จะขยายตัวเป็นสตริงว่างแทนอะไรเลยเมื่อรายการของพารามิเตอร์ตำแหน่งว่างเปล่า (คุณต้องทำงานไปรอบ ๆ ด้วย${1+"$@"}) ทำไมมันไม่ได้เก็บพารามิเตอร์ตำแหน่งที่ว่างเปล่าและทำไม"$@"didn ไม่ทำงานเมื่อ$IFSไม่มีอักขระเว้นวรรค

ความตั้งใจที่จะสามารถส่งผ่านรายการของอาร์กิวเมนต์คำต่อคำไปยังคำสั่งอื่น แต่ไม่ได้ทำงานอย่างถูกต้องสำหรับรายการที่ว่างเปล่าสำหรับองค์ประกอบที่ว่างเปล่าหรือเมื่อ$IFSไม่ได้มีช่องว่าง (สองประเด็นแรกถูกแก้ไขในรุ่นต่อมาในที่สุด )

Korn เชลล์ (ซึ่งอิงกับ POSIX spec) เปลี่ยนพฤติกรรมดังกล่าวในสองสามวิธี:

  • การแยก IFS ทำได้เฉพาะกับผลลัพธ์ของการขยายที่ไม่ได้ยกมา (ไม่ใช่คำที่เป็นตัวอักษรเช่นeditหรือfile.txtในตัวอย่างด้านบน)
  • $*และ$@ถูกรวมเข้ากับอักขระตัวแรกของ$IFSหรือช่องว่างเมื่อ$IFSว่างเปล่ายกเว้นเครื่องหมาย"$@"อัญประกาศตัวเชื่อมนั้นไม่ถูกยกมาเหมือนในเชลล์เป้าหมายและสำหรับการอ้างอิง"$*"เมื่อIFSว่างเปล่าพารามิเตอร์ตำแหน่งจะถูกต่อท้ายโดยไม่มีตัวคั่น
  • มันเพิ่มการสนับสนุนสำหรับอาร์เรย์และ${array[@]} ${array[*]}เตือนความทรงจำของ Bourne $*และ$@แต่เริ่มต้นที่ดัชนี 0 แทนที่จะเป็น 1 และกระจัดกระจาย (เช่นเชื่อมโยงอาร์เรย์) ซึ่งหมายความว่า$@ไม่สามารถถือว่าเป็นอาร์เรย์ ksh จริงๆ (เปรียบเทียบกับcsh/ rc/ zsh/ fish/ yashที่ไหน$argv/ $*เป็นปกติ อาร์เรย์)
  • องค์ประกอบที่ว่างเปล่าจะถูกเก็บรักษาไว้
  • "$@"เมื่อ$#เป็น 0 ตอนนี้ขยายเป็นไม่มีอะไรแทนสตริงว่าง"$@"ทำงานเมื่อ$IFSไม่มีช่องว่างยกเว้นเมื่อIFSว่างเปล่า unquote ที่$*ไม่มี wildcard จะขยายเป็นหนึ่งอาร์กิวเมนต์ (โดยที่พารามิเตอร์ตำแหน่งถูกรวมเข้ากับช่องว่าง) เมื่อ$IFSว่างเปล่า

ksh93 แก้ไขปัญหาบางอย่างที่เหลืออยู่ด้านบน ใน ksh93, $*และ$@ขยายไปยังรายการของพารามิเตอร์ตำแหน่งที่แยกออกจากกันโดยไม่คำนึงถึงความคุ้มค่าของ$IFSแล้วแยกเพิ่มเติม + globbed + รั้งขยายตัวในบริบทรายการ$*ร่วมกับครั้งแรกไบต์ (ไม่ใช่ตัวอักษร) ของ$IFS, "$@"ในรายการบริบทขยายไปยังรายการ $IFSของพารามิเตอร์ตำแหน่งโดยไม่คำนึงถึงความคุ้มค่าของ ในบริบทที่ไม่ใช่รายการเหมือนในvar=$@, จะเข้าร่วมกับพื้นที่โดยไม่คำนึงถึงความคุ้มค่าของ$@$IFS

bashอาร์เรย์ของถูกออกแบบมาหลังจาก ksh ความแตกต่างคือ:

  • ไม่มีการขยายรั้งเมื่อการขยายที่ไม่ได้กล่าวถึง
  • อักขระตัวแรกของ$IFSแทนไบต์
  • ความแตกต่างของมุมกรณีบางอย่างเช่นการขยายตัวของ$*เมื่อไม่อ้างถึงในบริบทที่ไม่ใช่รายการเมื่อ$IFSว่างเปล่า

ในขณะที่ข้อมูลจำเพาะ POSIX เคยเป็นค่อนข้างคลุมเครือตอนนี้มันมากหรือน้อยระบุพฤติกรรมทุบตี

มันแตกต่างจากอาร์เรย์ปกติในkshหรือbashที่:

  • ดัชนีเริ่มต้นที่ 1 แทน 0 (ยกเว้น"${@:0}"ซึ่งรวมถึง$0(ไม่ใช่พารามิเตอร์ตำแหน่งและในฟังก์ชั่นให้ชื่อของฟังก์ชั่นหรือไม่ขึ้นอยู่กับเปลือกและวิธีการกำหนดฟังก์ชั่น)
  • คุณไม่สามารถกำหนดองค์ประกอบเป็นรายบุคคล
  • มันไม่กระจัดกระจายคุณไม่สามารถแยกองค์ประกอบได้ทีละรายการ
  • shift สามารถใช้ได้.

ในzshหรือyashที่อาร์เรย์เป็นอาร์เรย์ปกติ (ไม่กระจัดกระจายดัชนีเริ่มต้นที่หนึ่งเหมือนในเปลือกอื่น ๆ ทั้งหมด แต่ ksh / bash) $*จะถือว่าเป็นอาร์เรย์ปกติ zshมี$argvเป็นนามแฝงสำหรับมัน (เพื่อความเข้ากันได้กับcsh) $*เหมือนกับ$argvหรือ${argv[*]}(อาร์กิวเมนต์เข้าร่วมกับอักขระตัวแรกของ$IFSแต่ยังแยกออกในบริบทรายการ) "$@"ชอบ"${argv[@]}"หรือ"${*[@]}"}ผ่านกระบวนการพิเศษในสไตล์กร


8

อย่างไรก็ตามฉันไม่รู้ว่าโครงสร้างข้อมูล$@คืออะไร

มันเป็นพารามิเตอร์พิเศษที่ขยายไปถึงค่าของพารามิเตอร์ตำแหน่ง ... แต่นั่นก็เป็นเรื่องที่เกี่ยวกับคำศัพท์

เราสามารถดูพารามิเตอร์ตำแหน่งเป็นส่วนหนึ่ง$@ได้ดังนั้นจึงมีองค์ประกอบที่แตกต่างจำนวนมาก ( $1, $2... ) ที่สามารถเข้าถึงได้อย่างอิสระและตั้งชื่อตามหมายเลขธรรมชาติติดต่อกัน ทำให้บางสิ่งบางอย่างที่มักจะเรียกว่าอาเรย์

ไวยากรณ์เป็นบิตแปลก แต่และแม้กระทั่ง จำกัด ไม่มีวิธีใดที่จะแก้ไของค์ประกอบเดี่ยวของอาร์เรย์ทีละรายการ แต่จะต้องตั้งค่าทั้งหมดทันที (คุณสามารถใช้set -- "$@" fooเพื่อผนวกค่าหรือset -- "${@:1:2}" foo "${@:3}"เพื่อเพิ่มค่าที่อยู่ตรงกลาง แต่ในทั้งสองกรณีคุณต้องเขียนรายการผลลัพธ์ทั้งหมด)

ทำไมมันทำงานแตกต่างกับ$*เมื่อรวมอยู่ในเครื่องหมายคำพูดคู่

เพราะพวกมันถูกกำหนดให้ประพฤติแตกต่างกัน

อย่างไรก็ตามมันยังสามารถสะท้อนได้อย่างง่ายดายecho $@ถ้าเป็นอาร์เรย์จะมีเพียงองค์ประกอบแรกเท่านั้นที่แสดง

ถ้าคุณหมายถึงความจริงที่ว่าa=(foo bar asdf); echo $aออกจะเพียงแค่fooนี้แล้วเป็นส่วนใหญ่เป็นมุมแหลมของไวยากรณ์เปลือกและความจริงที่ว่า ksh $@สไตล์ชื่ออาร์เรย์ที่ถูกสร้างขึ้นช้ากว่าพารามิเตอร์ตำแหน่งและ ล้วน$aมีความเหมือนกัน${a[0]}ดังนั้นจึงมีความหมายที่เข้ากันได้แบบย้อนหลังของค่าสเกลาร์เดี่ยวโดยไม่คำนึงว่าaอาร์เรย์หรือตัวแปรสเกลาร์ง่าย

@สัญญาณหมายถึงรายชื่อทั้งหมดถูกนำกลับมาใช้กับอาร์เรย์มีชื่ออยู่ในนั้น"${a[@]}"เป็นวิธีที่จะได้รับรายชื่อทั้งหมด เมื่อเปรียบเทียบกับอาร์เรย์ที่มีชื่อด้วย$@วงเล็บปีกกาและวงเล็บปีกกาที่ไม่จำเป็นและชื่อจะถูกข้ามไป

หรือในคำอื่น ๆ ฉันต้องการทราบวิธีการ$@เก็บไว้ในหน่วยความจำคอมพิวเตอร์

ขึ้นอยู่กับการนำไปใช้งานคุณจะต้องดูซอร์สโค้ดของเชลล์ใด ๆ ที่คุณสนใจ

มันเป็นสตริงสตริงหลายบรรทัดหรืออาร์เรย์หรือไม่?

อาเรย์ส่วนใหญ่ แม้ว่าจะแตกต่างจากอาร์เรย์ ksh $@สไตล์ชื่อเนื่องจากพวกเขาสามารถมีพลจำนวนเต็มไม่ติดลบเป็นดัชนีไม่ได้คนเพียงติดต่อกันเช่นเดียวกับ (นั่นคือชื่ออาร์เรย์สามารถเบาบางและมีเช่นดัชนี1, 3และ4ด้วย0และ2ที่ขาดหายไป. นั่นเป็นไปไม่ได้กับพารามิเตอร์ตำแหน่ง.)

ไม่ใช่สตริงเดี่ยวเนื่องจากสามารถขยายไปยังองค์ประกอบที่แตกต่างกันและการเรียกบรรทัดองค์ประกอบนั้นไม่ถูกต้องเนื่องจากตัวแปรปกติใด ๆ หรือหนึ่งในพารามิเตอร์ตำแหน่ง (องค์ประกอบของ$@) สามารถมีการขึ้นบรรทัดใหม่ได้

หากเป็นชนิดข้อมูลที่ไม่ซ้ำใครเป็นไปได้ไหมที่จะกำหนดตัวแปรที่กำหนดเองเป็นตัวอย่างของประเภทนี้

ไม่ แต่อาร์เรย์ที่ตั้งชื่ออาจมีประโยชน์มากกว่านี้แล้ว


1
+1 TL: DR $@ไม่ใช่โครงสร้างข้อมูล แต่เป็นหนึ่งในไม่กี่ฟังก์ชัน / ตัวดำเนินการสำหรับการขยายโครงสร้างข้อมูลพารามิเตอร์ตำแหน่ง
Peter Cordes
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.