ตัวแปรอ้างอิงในเชลล์สคริปต์


10

ในเชลล์สคริปต์ถ้าฉันกำหนดตัวแปรเช่นFOO=25มีความแตกต่างระหว่างการอ้างอิงเป็น$FOO$และ${FOO}$?


2
คุณต้องไม่ใช้$ในที่สุด! มันจะถือว่าเป็นตัวอักษรปกติและไม่เป็นส่วนหนึ่งของชื่อตัวแปร
ผู้บัญชาการไบต์

คำตอบ:


16

ในสถานการณ์ส่วนใหญ่ทั้งสอง$varและ${var}เหมือนกัน (โปรดทราบว่าคุณจะต้องไม่ใช้$ท้าย!)

ตัวอย่างหนึ่งที่คุณต้องการวงเล็บปีกกาคือเมื่อคุณต้องการใส่ตัวแปรในสายอักขระต่อเนื่อง

ตัวอย่าง:

var=hel
echo ${var}lo

helloออกจะ


11

ที่จะตอบคำถามหลักของคุณ${foo}เรียกว่า"การขยายตัวพารามิเตอร์" เพื่อความแม่นยำ$ตัวเองจะเริ่มการขยายตัวของพารามิเตอร์ตัว{ }เลือกจริงตามข้อกำหนด POSIXแต่มีประโยชน์ในการระบุจุดสิ้นสุดของชื่อตัวแปร:

$ foo="bar"
$ echo $fooBaz   ## fails, no variable named $fooBaz exists

$ echo ${foo}Baz ## works, $foo is expanded and the string Baz is appended
barBaz

โดยทั่วไป$fooและ${foo}เหมือนกัน นอกเหนือจากกรณีเช่นข้างต้นหรือเมื่อคุณทำการจัดการสตริงพวกเขาจะเทียบเท่าอย่างสมบูรณ์

อย่างไรก็ตามคุณไม่ควรใช้อย่างใดอย่างหนึ่ง กฎของหัวแม่มือคือว่ามีข้อยกเว้นน้อยมากที่คุณควรเสมอใช้"$foo"หรือ"${foo}"และไม่เคยหรือ$foo ${foo}คุณควรอ้างอิงตัวแปรของคุณเสมอเพื่อหลีกเลี่ยงการเรียกใช้ตัวดำเนินการแยก + glob (เพิ่มเติมในภายหลัง) $foo$แน่นอนคุณไม่ต้องการ รอบชิงชนะเลิศ$ไม่เกี่ยวข้อง:

$ foo="bar"
$ echo "$foo$"
bar$

ดังนั้นในขณะที่ตัวแปร unquote บางครั้งก็โอเค:

$ echo $foo
bar

พวกเขามักจะไม่และควรหลีกเลี่ยงจริง ๆ :

$ if [ -n $foo ]; then echo empty; else echo "not empty"; fi ## fails
empty

$ if [ -n "$foo" ]; then echo empty; else echo "not empty"; fi ## works
not empty

โปรดทราบว่าวงเล็บไม่ได้ช่วยที่นี่:

$ if [ -n ${foo} ]; then echo empty; else echo "not empty"; fi  ## fails
empty

$ if [ -n "${foo}" ]; then echo empty; else echo "not empty"; fi ## works
not empty

เมื่อคุณใช้$fooหรือ${foo}เชลล์จะแบ่งค่าที่บันทึกไว้ในตัวแปรในช่องว่าง (ซึ่งสามารถเปลี่ยนแปลงได้โดยการตั้งค่าIFSตัวแปรเป็นอย่างอื่น) ลงในรายการจากนั้นแต่ละองค์ประกอบของรายการจะถือว่าเป็นรูปแบบกลมและขยายเป็น ไฟล์หรือไดเรกทอรีที่ตรงกัน นี้เป็นที่รู้จักกันแยก + globผู้ประกอบการ หากต้องการแสดงตัวอย่างให้พิจารณาไดเร็กทอรีที่มีสองไฟล์:

$ ls -l
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file1
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file2

ตอนนี้เรามาตั้งค่าตัวแปรเป็นfoo *:

$ foo="foo *"

จะเกิดอะไรขึ้นถ้าเราพยายามตรวจสอบว่ามีไฟล์ชื่อนั้นอยู่หรือไม่?

$ if [ -e $foo ]; then echo "file exists"; else echo "no such file"; fi
file exists

ตัวแปรถูกแบ่งออกเป็นfooและ*เนื่องจาก*เป็น wildcard ที่ตรงกับสตริงใด ๆ เชลล์จะบอกคุณว่าไฟล์ชื่อfoo *exxists อย่างไรก็ตามหากเราพูดอย่างถูกต้องสิ่งนี้จะไม่เกิดขึ้น:

$ if [ -e "$foo" ]; then echo "file exists"; else echo "no such file"; fi
no such file

นั่นเป็นตัวอย่างเล็กน้อยเพื่อแสดงจุด ลองคิดดูหากผมใช้rmแทนechoแม้ว่า

ดังนั้นกฎข้อแรก: อ้างอิงตัวแปรของคุณเสมอ คุณสามารถใช้อย่างใดอย่างหนึ่ง"$foo"หรือ"${foo}"แต่อ้างอิงมันด้วยวิธีใดวิธีหนึ่ง สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับการใช้ตัวแปรอย่างปลอดภัยดูที่โพสต์เหล่านี้:


ผมไม่ได้ต้องการที่จะแก้ไขคำตอบที่ดีมิฉะนั้นคุณ แต่ไม่ควร$ var="foo *"จะเป็น$ foo="foo *"? คุณไม่ได้ใช้varทุกที่
โจ

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