การขยายตัวทางอ้อมคืออะไร? $ {! var *} หมายความว่าอย่างไร


87

ฉันกำลังอ่าน " Bash Guide for Beginners " มันบอกว่า:

ถ้าอักขระตัวแรกของPARAMETERเป็นเครื่องหมายอัศเจรีย์ Bash จะใช้ค่าของตัวแปรที่สร้างขึ้นจากส่วนที่เหลือPARAMETERเป็นชื่อของตัวแปร จากนั้นตัวแปรนี้จะถูกขยายและค่านั้นจะถูกใช้ในส่วนที่เหลือของการทดแทนแทนที่จะเป็นค่าของPARAMETERตัวมันเอง สิ่งนี้เรียกว่าการขยายตัวทางอ้อม

ตัวอย่างที่ให้คือ:

franky ~> echo ${!N*}
NNTPPORT NNTPSERVER NPX_PLUGIN_PATH

ฉันไม่ค่อยเข้าใจที่นี่:

ค่าของตัวแปรที่เกิดจากส่วนที่เหลือของ PARAMETER

ตามที่PARAMETERเป็นธรรม!N*แล้ว

ส่วนที่เหลือของ PARAMETER

N*เป็นเพียง สิ่งนี้สร้างตัวแปรได้อย่างไร? Bash ค้นหาคำสั่งที่เป็นไปได้ทั้งหมดหรือไม่?

คำตอบ:


112

หากคุณอ่านbashหน้าคนโดยทั่วไปจะเป็นการยืนยันสิ่งที่คุณระบุไว้:

หากอักขระตัวแรกของพารามิเตอร์เป็นเครื่องหมายอัศเจรีย์ ( !) ระดับของตัวแปรอินดิเรต Bash ใช้ค่าของตัวแปรที่สร้างจากพารามิเตอร์ที่เหลือเป็นชื่อของตัวแปร จากนั้นตัวแปรนี้จะถูกขยายและค่านั้นจะถูกใช้ในส่วนที่เหลือของการทดแทนแทนที่จะเป็นค่าของพารามิเตอร์เอง สิ่งนี้เรียกว่าการขยายตัวทางอ้อม

อย่างไรก็ตามอ่านต่อจากที่นั่น:

ข้อยกเว้นนี้คือการขยาย${!prefix*}และ${!name[@]}อธิบายไว้ด้านล่าง

${!prefix*}ชื่อที่ตรงกับคำนำหน้า ขยายเป็นชื่อของตัวแปรที่ชื่อขึ้นต้นด้วยคำนำหน้าคั่นด้วยอักขระตัวแรกของIFSตัวแปรพิเศษ

กล่าวอีกนัยหนึ่งตัวอย่างเฉพาะของคุณ${!N*}เป็นข้อยกเว้นของกฎที่คุณยกมา มันไม่แต่การทำงานตามที่โฆษณาในกรณีที่คาดว่าเช่น:

$ export xyzzy=plugh ; export plugh=cave

$ echo ${xyzzy}  # normal, xyzzy to plugh
plugh

$ echo ${!xyzzy} # indirection, xyzzy to plugh to cave
cave

1
ขอบคุณสำหรับคำตอบ. ยิ่งฉันอ่าน "Bash guide for Beginners" มากเท่าไหร่ฉันก็ยิ่งถามตัวเองมากขึ้นว่าผู้เขียนเข้าใจสิ่งที่เธอเขียนหรือไม่
LRDPRDX

24

ดูเหมือนจะมีข้อยกเว้นเมื่อ "indirection" ที่ระบุลงท้ายด้วย a *เช่นเดียวกับที่นี่ ในกรณีนี้จะให้ชื่อตัวแปรทั้งหมดที่ขึ้นต้นด้วยส่วนที่คุณระบุ ( Nที่นี่) Bash สามารถทำได้เพราะมันติดตามตัวแปรและรู้ว่ามีตัวแปรใดบ้าง

ทรูตรงนี้คือ:
ว่าฉันมีตัวแปร$VARIABLEชุด42และฉันมีอีกตัวแปรชุด $NAME จะให้ฉัน คุณใช้ค่าของตัวแปรหนึ่งเพื่อบอกชื่อของตัวแปรอื่น:VARIABLE${!NAME}42

$ NAME="VARIABLE"
$ VARIABLE=42
$ echo ${!NAME}
42

6
ว้าวใครจะรู้ว่ามันง่ายมากที่จะได้รับคำตอบเกี่ยวกับความหมายของชีวิตจักรวาลและทุกสิ่ง!
KomodoDave

3

ใช่มันค้นหาการขยายตัวแปรที่เป็นไปได้ทั้งหมดหลังจาก! หากคุณทำ:

echo ${!NP*}

NPX_PLUGIN_PATHคุณจะได้รับเท่านั้น

พิจารณาตัวอย่างต่อไปนี้:

:~> export myVar="hi"
:~> echo ${!my*}
    myVar
:~> export ${!my*}="bye"
:~> echo $myVar
    bye

ตัวแปรอื่น ๆ ที่ตรงกับ * ของฉันจะถูกตั้งค่าเป็น "ลาก่อน" ด้วยหรือไม่
Anthony

1
@Anthony ฉันลองแล้วและถ้า${!my*}ขยายเป็น myA, myB, myA จะถูกส่งออกด้วยค่าปัจจุบันและ myB ถูกตั้งค่าเป็น "ลาก่อน" และส่งออก ไม่ค่อยมีประโยชน์.
GKFX

3

คุณได้รับข้อยกเว้นในการประมวลผลแบบทิศทางโดยที่หากอักขระตัวสุดท้ายเป็น*ตัวแปรทั้งหมดที่มีคำนำหน้าก่อนหน้านี้จะถูกส่งกลับ


นอกเหนือจาก*กรณีนี้จะเหมือนกับ${${VAR}}หรือไม่?
chronospoon

1
@chronospoon ซึ่ง${${VAR}}เขียนได้ไม่นานเนื่องจาก${$VAR}ไม่ถูกกฎหมายเนื่องจาก$VARส่งคืนสตริงซึ่งไม่สามารถติดตาม$เครื่องหมายได้ ใช้สตริงเป็นชื่อตัวแปรที่คุณต้องการที่จะแนะนำหนึ่งระดับของความร้าย (ตามที่อ้างถึงในคำถามเดิมของตัวเอง) คือคุณสามารถใช้${!VAR}ซึ่งไม่ตรงกับสิ่งที่คุณคาดหวัง (ไม่สมควร แต่เข้าใจ) ${$VAR}ไม่
Enlico

0

คุณสามารถอ้างถึงเอกสาร GNU นี้สำหรับ bash สำหรับข้อมูลที่เชื่อถือได้

https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html#Shell-Parameter-Expansion

แต่โดยพื้นฐานแล้วการขยายทางอ้อมไม่ได้ดำเนินการ ${!prefix*} เป็นหนึ่งในข้อยกเว้นในตัวอย่างของคุณ N คือคำนำหน้า

เอกสารจะอธิบายว่าการขยายทางอ้อมคืออะไรในการทุบตี

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