ตัวอย่างเช่น:
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
และใช้\
อักขระหนี:
me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR
เห็นได้ชัดว่าฉันทำอะไรโง่ ๆ
ฉันจะรับผลลัพธ์ได้BAR * BAR
อย่างไร
ตัวอย่างเช่น:
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
และใช้\
อักขระหนี:
me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR
เห็นได้ชัดว่าฉันทำอะไรโง่ ๆ
ฉันจะรับผลลัพธ์ได้BAR * BAR
อย่างไร
คำตอบ:
การอ้างถึงเมื่อการตั้งค่า$FOO
ไม่เพียงพอ คุณต้องอ้างการอ้างอิงตัวแปรด้วย:
me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
คำตอบสั้น ๆ
เช่นเดียวกับที่คนอื่น ๆ กล่าว - คุณควรอ้างตัวแปรเพื่อป้องกันพฤติกรรมแปลก ๆ ดังนั้นการใช้echo "$ foo"ในแทนเพียงecho $
คำตอบยาว ๆ
ฉันคิดว่าตัวอย่างนี้รับประกันคำอธิบายเพิ่มเติมเพราะมีอะไรเกิดขึ้นมากกว่าที่จะเห็น
ฉันเห็นว่าความสับสนของคุณเกิดขึ้นที่ไหนเพราะหลังจากที่คุณทำตัวอย่างแรกคุณอาจคิดไปเองว่าเชลล์กำลังทำอยู่
จากตัวอย่างแรกของคุณ:
me$ FOO="BAR * BAR"
me$ echo $FOO
หลังจากการขยายพารามิเตอร์เทียบเท่ากับ:
me$ echo BAR * BAR
และหลังจากการขยายชื่อไฟล์เทียบเท่ากับ:
me$ echo BAR file1 file2 file3 file4 BAR
และถ้าคุณพิมพ์echo BAR * BAR
ลงในบรรทัดคำสั่งคุณจะเห็นว่าเทียบเท่ากัน
คุณคงคิดไปเองว่า "ถ้าฉันหนี * ฉันสามารถป้องกันการขยายชื่อไฟล์ได้"
จากตัวอย่างที่สองของคุณ:
me$ FOO="BAR \* BAR"
me$ echo $FOO
หลังจากการขยายพารามิเตอร์ควรเทียบเท่ากับ:
me$ echo BAR \* BAR
และหลังจากการขยายชื่อไฟล์ควรเทียบเท่ากับ:
me$ echo BAR \* BAR
และถ้าคุณลองพิมพ์ "echo BAR \ * BAR" ลงในบรรทัดคำสั่งโดยตรงมันจะพิมพ์ "BAR * BAR" เนื่องจากการขยายชื่อไฟล์ถูกป้องกันโดยการ Escape
เหตุใดการใช้ $ foo จึงไม่ได้ผล?
เป็นเพราะมีส่วนขยายที่สามเกิดขึ้น - การลบใบเสนอราคา จากการลบใบเสนอราคาด้วยตนเองคือ:
หลังจากการขยายก่อนหน้านี้อักขระ '\', '' 'และ' "'ที่ไม่ได้ใส่เครื่องหมายคำพูดทั้งหมดที่ไม่ได้เป็นผลจากการขยายข้างต้นจะถูกลบออก
สิ่งที่เกิดขึ้นคือเมื่อคุณพิมพ์คำสั่งลงในบรรทัดคำสั่งโดยตรงอักขระหนีไม่ได้เป็นผลลัพธ์ของส่วนขยายก่อนหน้าดังนั้น BASH จึงลบออกก่อนที่จะส่งไปยังคำสั่ง echo แต่ในตัวอย่างที่ 2 "\ *" คือ ผลลัพธ์ของการขยายพารามิเตอร์ก่อนหน้านี้จึงไม่ถูกลบออก ด้วยเหตุนี้เสียงสะท้อนจึงได้รับ "\ *" และนั่นคือสิ่งที่พิมพ์ออกมา
โปรดสังเกตความแตกต่างระหว่างตัวอย่างแรก - "*" ไม่รวมอยู่ในอักขระที่จะถูกลบโดยการลบใบเสนอราคา
ฉันหวังว่านี่จะสมเหตุสมผล ในท้ายที่สุดข้อสรุปเดียวกัน - เพียงแค่ใช้เครื่องหมายคำพูด ฉันแค่คิดว่าฉันจะอธิบายว่าทำไมการหลบหนีซึ่งตามเหตุผลควรใช้งานได้ถ้ามีเพียงการขยายพารามิเตอร์และชื่อไฟล์เท่านั้นที่ไม่ทำงาน
สำหรับคำอธิบายทั้งหมดของการขยาย BASH โปรดดูที่:
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions
ฉันจะเพิ่มเล็กน้อยในกระทู้เก่านี้
โดยปกติคุณจะใช้
$ echo "$FOO"
อย่างไรก็ตามฉันมีปัญหากับไวยากรณ์นี้ พิจารณาสคริปต์ต่อไปนี้
#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"
*
ความต้องการที่จะส่งผ่านคำต่อคำไปcurl
แต่ปัญหาเดียวกันจะเกิดขึ้น ตัวอย่างข้างต้นใช้ไม่ได้ (จะขยายเป็นชื่อไฟล์ในไดเรกทอรีปัจจุบัน) และจะไม่ทำ\*
เช่นนั้น นอกจากนี้คุณยังไม่สามารถพูด$curl_opts
เพราะมันจะได้รับการยอมรับเป็นหนึ่งเดียว (ไม่ถูกต้อง) curl
เลือกที่จะ
curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
ดังนั้นฉันขอแนะนำให้ใช้bash
ตัวแปร$GLOBIGNORE
เพื่อป้องกันการขยายชื่อไฟล์โดยสิ้นเชิงหากใช้กับรูปแบบส่วนกลางหรือใช้set -f
แฟล็กในตัว
#!/bin/bash
GLOBIGNORE="*"
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1" ## no filename expansion
นำไปใช้กับตัวอย่างเดิมของคุณ:
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
me$ set -f
me$ echo $FOO
BAR * BAR
me$ set +f
me$ GLOBIGNORE=*
me$ echo $FOO
BAR * BAR
SELECT * FROM etc.
นี่เป็นวิธีเดียวที่ใช้ได้ผล
echo "$FOO"
มันอาจจะมีมูลค่าที่ได้รับในนิสัยของการใช้printf
มากกว่านั้นecho
ในบรรทัดคำสั่ง
ในตัวอย่างนี้ไม่ได้ให้ประโยชน์มากนัก แต่มีประโยชน์มากกว่าด้วยเอาต์พุตที่ซับซ้อนกว่า
FOO="BAR * BAR"
printf %s "$FOO"