ทุบตีให้การสนับสนุนสำหรับการใช้ตัวชี้?


12

คำถามง่าย ๆ เปลือก bash มีการสนับสนุนการใช้พอยน์เตอร์เมื่อเขียนเชลล์สคริปต์หรือไม่?

ฉันคุ้นเคยกับสัญกรณ์การขยายตัว${var[@]}เมื่อทำการวนซ้ำอาร์เรย์$varแต่ไม่ชัดเจนว่านี่เป็นการใช้พอยน์เตอร์เพื่อย้ำข้ามดัชนีอาร์เรย์ ทุบตีให้การเข้าถึงที่อยู่หน่วยความจำเช่นภาษาอื่น ๆ ?

หาก bash ไม่สนับสนุนการใช้พอยน์เตอร์เชลล์อื่นจะทำอะไร?

คำตอบ:


28

ตัวชี้ (ไปยังตำแหน่งของหน่วยความจำ ) ไม่ใช่แนวคิดที่มีประโยชน์ในระดับที่สูงกว่า C ไม่ว่าจะเป็น Python หรือเชลล์ แน่นอนการอ้างอิงไปยังวัตถุมีประโยชน์ในภาษาระดับสูงบางทีอาจจำเป็นสำหรับการสร้างโครงสร้างข้อมูลที่ซับซ้อน แต่ในกรณีส่วนใหญ่การคิดในแง่ของที่อยู่หน่วยความจำอยู่ในระดับต่ำเกินไปที่จะมีประโยชน์มาก

ในทุบตี (และหอยอื่น ๆ ) คุณจะได้รับค่าขององค์ประกอบมากมายกับที่${array[index]}สัญกรณ์กำหนดพวกเขาด้วยและได้รับจำนวนขององค์ประกอบในอาร์เรย์ที่มีarray[index]=... ${#array[@]}การแสดงออกภายในวงเล็บคือการแสดงออกทางคณิตศาสตร์ เป็นตัวอย่างที่สร้างขึ้นเราสามารถเพิ่มคำนำหน้าคงที่ให้กับสมาชิกอาเรย์ทั้งหมด:

for ((i=0 ; i < ${#array[@]} ; i++ )) ; do
    array[i]="foo-${array[i]}"
done

(ถ้าเราใส่ใจเฉพาะค่าและไม่ใช่ดัชนีเพียง แต่for x in "${array[@]}" ; do...จะไม่เป็นไร)

ด้วยอาเรย์แบบเชื่อมโยงหรือกระจัดกระจายการวนรอบตัวเลขไม่สมเหตุสมผล แต่เราต้องการดึงคีย์ / ดรรชนีอาเรย์${!array[@]}แทน เช่น

declare -A assoc=([foo]="123" [bar]="456")
for i in "${!assoc[@]}" ; do 
    echo "${assoc[$i]}"
done 

นอกจากนั้น Bash มีสองวิธีในการชี้ทางอ้อมไปยังตัวแปรอื่น:

  • การขยายตัวทางอ้อมโดยใช้ไวยากรณ์ซึ่งใช้ค่าของตัวแปรที่มีชื่ออยู่ในและ${!var}var
  • namerefsซึ่งจะต้องสร้างขึ้นด้วยdeclarebuiltin (หรือ - kshพ้องความหมายที่เข้ากันได้typeset) declare -n ref=varทำให้มีการอ้างอิงถึงตัวแปรrefvar

Namerefs การจัดทำดัชนียังสนับสนุนในว่าถ้าเรามีarr=(a b c); declare -n ref=arr;แล้วจะขยายไปยัง${ref[1]} bการใช้${!p[1]}จะใช้pเป็นอาร์เรย์แทนและอ้างถึงตัวแปรที่ตั้งชื่อโดยองค์ประกอบที่สอง

ใน Bash namerefs นั้นแท้จริงแล้วอ้างอิงโดยชื่อและการใช้ nameref จากภายในฟังก์ชั่นจะใช้ค่าท้องถิ่นของตัวแปรที่มีชื่อ local value of varนี้จะพิมพ์

#!/bin/bash
fun() {
        local var="local value of var"
        echo "$ref";
}
var="global var"
declare -n ref=var
fun

BashFAQ มีบทความยาวเกี่ยวกับการอ้อมเช่นกัน


2
การอ้อมค้อมค่อนข้างมีประโยชน์ในภาษาระดับสูงกว่า เช่นการอ้างอิงใน Perl พวกมันไม่เหมือนกับตัวชี้ C แต่ให้บริการฟังก์ชันพื้นฐานที่เหมือนกัน แม้แต่ทุบตีสามารถเข้าถึงตัวแปรทางอ้อม ... แต่ IMO ถ้าคุณเริ่มเขียนโค้ดที่ใช้คุณลักษณะนี้อย่างมีนัยสำคัญคุณจะดีกว่าถ้าเริ่มจากศูนย์ด้วย Perl หรืออะไร ดูเพิ่มเติมmywiki.wooledge.org/BashFAQ/006
cas

2
@cas โอ้อย่างแน่นอน แต่อาจเป็นการดีกว่าถ้าคิดว่าการชี้ไปที่วัตถุไม่ใช่ที่อยู่หน่วยความจำ (แม้กระทั่งใน C มีประเภทที่เกี่ยวข้อง) ฉันตั้งใจจะบันทึกทั้งการขยายตัวทางอ้อมและ namerefs แต่ไม่มีเวลาที่จะทำทันที
ilkkachu

อาจเป็นสิ่งที่ควรค่าแก่การชี้ให้เห็นว่าตัวอย่าง for-loop นั้นถูกเขียนขึ้นอย่างเป็นธรรมชาติมากขึ้นfor foo in "${array[@]}" ; do ... doneถ้าคุณไม่ต้องการดัชนีสำหรับจุดประสงค์อื่น
Will Crawford จะ

@ WillCrawford ชี้ไปที่ แก้ไขตัวอย่างและจดบันทึก
ilkkachu

9

ไม่ไม่มีbash"ตัวชี้" แต่มีการอ้างอิง:

$ spam="fred"
$ declare -n tripe=spam
$ echo $tripe
fred
$ tripe=juki
$ echo $spam
juki

จากbashหน้าคน:

ตัวแปรสามารถกำหนดแอตทริบิวต์ nameref โดยใช้ตัวเลือก -n ไปที่คำสั่งdeclareหรือlocalbuiltin เพื่อสร้าง nameref หรืออ้างอิงกับตัวแปรอื่น สิ่งนี้อนุญาตให้ตัวแปรถูกควบคุมทางอ้อม เมื่อใดก็ตามที่มีการอ้างอิงตัวแปร nameref กำหนดให้ยกเลิกกำหนดหรือปรับเปลี่ยนแอตทริบิวต์ (นอกเหนือจากการใช้หรือเปลี่ยนแอตทริบิวต์ nameref เอง) การดำเนินการจะดำเนินการกับตัวแปรที่ระบุโดยค่าของตัวแปร nameref โดยทั่วไปแล้ว nameref จะใช้ในฟังก์ชั่นเชลล์เพื่ออ้างถึงตัวแปรที่มีชื่อถูกส่งเป็นอาร์กิวเมนต์ของฟังก์ชัน ตัวอย่างเช่นหากชื่อตัวแปรถูกส่งผ่านไปยังฟังก์ชันเชลล์เป็นอาร์กิวเมนต์แรกให้เรียกใช้

declare -n ref=$1

ภายในฟังก์ชั่นสร้างการอ้างอิงตัวแปร nameref ที่มีค่าเป็นชื่อตัวแปรที่ส่งผ่านเป็นอาร์กิวเมนต์แรก การอ้างอิงและการมอบหมายให้อ้างอิงและการเปลี่ยนแปลงคุณสมบัติจะถือเป็นการอ้างอิงการมอบหมายและการปรับเปลี่ยนแอตทริบิวต์ของตัวแปรที่มีชื่อถูกส่งเป็น $ 1 หากตัวแปรควบคุมใน for for มีแอ็ตทริบิวต์ nameref รายการคำสามารถเป็นรายการของตัวแปรเชลล์และการอ้างอิงชื่อจะถูกสร้างขึ้นสำหรับแต่ละคำในรายการในทางกลับกันเมื่อมีการดำเนินการลูป ตัวแปร Array ไม่สามารถกำหนดแอตทริบิวต์ nameref ได้ อย่างไรก็ตามตัวแปร nameref สามารถอ้างอิงตัวแปรอาร์เรย์และตัวแปรอาร์เรย์ที่ห้อยลงมาได้ Namerefs สามารถยกเลิกการตั้งค่าโดยใช้ตัวเลือก -n เพื่อunsetbuiltin มิฉะนั้นถ้าunset ถูกเรียกใช้งานโดยชื่อของตัวแปร nameref เป็นอาร์กิวเมนต์ตัวแปรที่อ้างอิงโดยตัวแปร nameref จะไม่ถูกตั้งค่า


4

ไม่เชลล์ไม่ได้ใช้ "พอยน์เตอร์" (ดังที่เข้าใจใน C)

อาร์เรย์สามารถใช้ดัชนี: echo "${array[2]}"แต่@ในตัวอย่างของคุณไม่ใช่ "ตัวชี้" จริงๆ มันเป็นวิธีที่จะแสดง "รายการของค่าอาร์เรย์" สิ่งที่ตัวแยกวิเคราะห์เชลล์เข้าใจ คล้ายกับวิธี a:

$ echo "$@"

ขยายไปยังรายการ "พารามิเตอร์ตำแหน่ง" ทั้งหมด


2

ในขณะที่ bash จำนวนเต็มอาร์เรย์ดัชนีที่สามารถกำหนดและเข้าถึงได้ค่อนข้างเช่นนั้น

declare -a obj
obj+=("val1")
obj+=("val2")

for item in ${obj[@]}; do
  echo "${obj[${item}]} ${item}"
done

อาเรย์ที่เชื่อมโยงหรือสตริงตามดัชนีใน bash ต้องการนิยามซ้ำ ๆ ดังต่อไปนี้

declare -A obj
obj["key1"]="val1"
obj["key2"]="val2"

for item in ${!obj[@]}; do
  echo "${obj[${item}]} ${item}"
done

ในการตอบคำถามเกี่ยวกับพอยน์เตอร์และการใช้อย่างใดอย่างหนึ่งจาก bash; evalการทำงานภายในของไบนารีทุบตีรวบรวมไม่แน่นอนทำให้การใช้งานของตัวชี้การจัดสรรหน่วยความจำในกองและไม่เปิดเผยการทำงานคล้ายกับการใช้งานของ ดู [การอ้างอิงทางอ้อม] http://tldp.org/LDP/abs/html/ivr.html )

มีมังกร การใช้evalควรใช้ด้วยความระมัดระวังเนื่องจากผลกระทบการรักษาความปลอดภัย

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