เมื่อพวกเขาจะไม่ยกมา$*
และ$@
เหมือนกัน คุณไม่ควรใช้อย่างใดอย่างหนึ่งเหล่านี้เนื่องจากพวกเขาสามารถแตกโดยไม่คาดคิดทันทีที่คุณมีอาร์กิวเมนต์ที่มีช่องว่างหรืออักขระตัวแทน
"$*"
"$1c$2c..."
ขยายคำเดียว โดยปกติแล้วc
จะมีช่องว่าง แต่จริงๆแล้วมันเป็นตัวอักษรตัวแรกของIFS
ดังนั้นมันสามารถเป็นอะไรก็ได้ที่คุณเลือก
การใช้งานที่ดีอย่างเดียวที่ฉันเคยพบคือ:
เข้าร่วมข้อโต้แย้งด้วยเครื่องหมายจุลภาค (เวอร์ชันง่าย)
join1() {
typeset IFS=,
echo "$*"
}
join1 a b c # => a,b,c
เข้าร่วมข้อโต้แย้งด้วยตัวคั่นที่ระบุ (รุ่นที่ดีกว่า)
join2() {
typeset IFS=$1 # typeset makes a local variable in ksh (see footnote)
shift
echo "$*"
}
join2 + a b c # => a+b+c
"$@"
ขยายเป็นคำแยก: "$1"
"$2"
...
นี่คือสิ่งที่คุณต้องการเกือบทุกครั้ง มันขยายแต่ละพารามิเตอร์ตำแหน่งเป็นคำที่แยกต่างหากซึ่งทำให้มันสมบูรณ์แบบสำหรับการรับบรรทัดคำสั่งหรือฟังก์ชั่นการขัดแย้งในแล้วส่งพวกเขาไปยังคำสั่งหรือฟังก์ชั่นอื่น และเนื่องจากมันขยายโดยใช้เครื่องหมายคำพูดคู่หมายความว่าสิ่งต่าง ๆ ไม่แตกถ้าพูด"$1"
มีช่องว่างหรือเครื่องหมายดอกจัน ( *
)
ลองเขียนสคริปต์ที่เรียกว่าsvim
ที่ทำงานด้วยvim
sudo
เราจะทำสามเวอร์ชันเพื่อแสดงความแตกต่าง
svim1
#!/bin/sh
sudo vim $*
svim2
#!/bin/sh
sudo vim "$*"
svim3
#!/bin/sh
sudo vim "$@"
ทั้งหมดจะใช้ได้กับกรณีง่ายๆเช่นชื่อไฟล์เดียวที่ไม่มีช่องว่าง:
svim1 foo.txt # == sudo vim foo.txt
svim2 foo.txt # == sudo vim "foo.txt"
svim2 foo.txt # == sudo vim "foo.txt"
แต่จะใช้ได้$*
และ"$@"
ทำงานอย่างถูกต้องหากคุณมีหลายข้อโต้แย้ง
svim1 foo.txt bar.txt # == sudo vim foo.txt bar.txt
svim2 foo.txt bar.txt # == sudo vim "foo.txt bar.txt" # one file name!
svim3 foo.txt bar.txt # == sudo vim "foo.txt" "bar.txt"
และมีเพียง"$*"
และ"$@"
ทำงานอย่างถูกต้องหากคุณมีข้อโต้แย้งที่มีช่องว่าง
svim1 "shopping list.txt" # == sudo vim shopping list.txt # two file names!
svim2 "shopping list.txt" # == sudo vim "shopping list.txt"
svim3 "shopping list.txt" # == sudo vim "shopping list.txt"
ดังนั้น"$@"
จะทำงานได้อย่างถูกต้องตลอดเวลา
typeset
เป็นวิธีการสร้างตัวแปรท้องถิ่นในksh
( bash
และash
ใช้local
แทน) หมายความว่าIFS
จะคืนค่าเป็นค่าก่อนหน้าเมื่อฟังก์ชันส่งคืน สิ่งนี้มีความสำคัญเนื่องจากคำสั่งที่คุณเรียกใช้หลังจากนั้นอาจทำงานไม่ถูกต้องหากIFS
ตั้งค่าเป็นสิ่งที่ไม่ได้มาตรฐาน