การเข้าถึงบรรทัดคำสั่ง bash args $ @ vs $ *


327

ในหลาย ๆ คำถามและแบบฝึกหัด bash ฉันเห็นว่าฉันสามารถเข้าถึง args บรรทัดคำสั่งในสคริปต์ทุบตีได้สองวิธี:

$ ~ >cat testargs.sh 
#!/bin/bash

echo "you passed me" $*
echo "you passed me" $@

ซึ่งผลลัพธ์ใน:

$ ~> bash testargs.sh arg1 arg2
you passed me arg1 arg2
you passed me arg1 arg2

ความแตกต่างระหว่าง$*และ$@คืออะไร?
เมื่อใดจึงควรใช้อดีตและเมื่อใดจะใช้ภายหลัง


ลองดูคำตอบนี้: stackoverflow.com/a/842325/671366
codeling

การวิเคราะห์แบบคงที่ใน IntelliJ ถือecho "something $@"เป็นข้อผิดพลาด
Alex Cohn

คำตอบ:


437

ความแตกต่างจะปรากฏขึ้นเมื่อมีการอ้างถึงพารามิเตอร์พิเศษ ให้ฉันอธิบายความแตกต่าง:

$ set -- "arg  1" "arg  2" "arg  3"

$ for word in $*; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in $@; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in "$*"; do echo "$word"; done
arg  1 arg  2 arg  3

$ for word in "$@"; do echo "$word"; done
arg  1
arg  2
arg  3

อีกตัวอย่างหนึ่งเกี่ยวกับความสำคัญของการอ้างอิง: ทราบว่ามี 2 ช่องว่างระหว่าง "หาเรื่อง" และจำนวน แต่ถ้าฉันไม่สามารถพูด $ word:

$ for word in "$@"; do echo $word; done
arg 1
arg 2
arg 3

และใน bash "$@"เป็นรายการ "default" ที่จะวนซ้ำ:

$ for word; do echo "$word"; done
arg  1
arg  2
arg  3

65
+1 ฉันคิดเสมอว่าแนวคิดนี้แสดงให้เห็นได้ดีที่สุดจากตัวอย่างง่ายๆที่คู่มือทุบตีขาดไปอย่างสมบูรณ์
chepner

5
มีกรณีการใช้งานที่เป็นไปได้เมื่อใด$*หรือ"$*"อาจจำเป็นต้องใช้ & วัตถุประสงค์ไม่สามารถให้บริการโดย$@หรือ"$@"?
anishsane

5
เวอร์ชันใดที่เหมาะสำหรับสคริปต์ "wrapper" ซึ่งพารามิเตอร์สคริปต์จำเป็นต้องกลายเป็นพารามิเตอร์ของคำสั่งใหม่
Segfault

7
@Segfault ในกรณีนี้ให้เลือก"$@"เครื่องหมายคำพูดเสมอ
เกล็นแจ็คแมน

2
คำตอบนี้มีตัวอย่างที่มีประโยชน์ แต่น่าจะดีกว่าถ้ามันอธิบายกลไกที่อยู่เบื้องหลัง ทำไมมันจึงเป็นเช่นนี้
Lii

255

ตารางภาพรวมที่มีประโยชน์ดีจากBash แฮกเกอร์ Wiki :

$ * กับ $ @ table

โดยที่cในแถวที่สามเป็นอักขระตัวแรกของ$IFSInternal Field Separator ตัวแปรเชลล์

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


42
... โดยที่ "c" เป็นอักขระตัวแรกของ $ IFS
glenn jackman

39
... และ$IFSย่อมาจาก "Internal Field Separator"
Serge Stroobandt

นี่คือตัวอย่างซึ่งรวมถึงการป้อนข้อมูลที่ยกมา การป้อนข้อมูลก็มีความสำคัญเช่นกัน!
Serge Stroobandt

สมมติว่าฉันต้องการสร้างสคริปต์ตัวห่อหุ้มที่ไม่ทำอะไรเลยนอกจากเลียนแบบการทำงานของคำสั่ง wrapper ฉันควรใช้ไวยากรณ์ใดในการส่ง args จากสคริปต์ตัวตัดคำสั่งไปยังคำสั่งภายใน
Marinos

44

$ *

ขยายไปยังพารามิเตอร์ตำแหน่งโดยเริ่มจากหนึ่งพารามิเตอร์ เมื่อการขยายเกิดขึ้นภายในเครื่องหมายคำพูดคู่จะขยายเป็นคำเดียวโดยมีค่าของแต่ละพารามิเตอร์คั่นด้วยอักขระตัวแรกของตัวแปรพิเศษของ IFS นั่นคือ "$ *" เทียบเท่ากับ "$ 1c $ 2c ... " โดยที่ c คืออักขระตัวแรกของค่าของตัวแปร IFS หาก IFS ไม่ได้ตั้งค่าพารามิเตอร์จะถูกคั่นด้วยช่องว่าง หาก IFS เป็นโมฆะพารามิเตอร์จะเข้าร่วมโดยไม่ต้องคั่นตัวคั่น

$ @

ขยายไปยังพารามิเตอร์ตำแหน่งโดยเริ่มจากหนึ่งพารามิเตอร์ เมื่อการขยายเกิดขึ้นภายในเครื่องหมายคำพูดคู่พารามิเตอร์แต่ละตัวจะขยายเป็นคำแยกต่างหาก นั่นคือ "$ @" เทียบเท่ากับ "$ 1" "$ 2" ... หากการขยายสองครั้งเกิดขึ้นภายในคำการขยายตัวของพารามิเตอร์ตัวแรกจะถูกรวมเข้ากับส่วนเริ่มต้นของคำเดิมและการขยาย ของพารามิเตอร์สุดท้ายเข้าร่วมกับส่วนสุดท้ายของคำเดิม เมื่อไม่มีพารามิเตอร์ตำแหน่ง "$ @" และ $ @ จะขยายเป็นไม่มีอะไร (เช่นจะถูกลบออก)

ที่มา: Bash man


15

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

แน่นอน "$ @" ควรจะยกมา

http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST


1

ให้ตัวอย่างนี้อาจเน้นความแตกต่างระหว่าง "ที่" และ "asterix" ในขณะที่เราใช้พวกเขา ฉันประกาศ "ผลไม้" และ "ผัก" สองอาร์เรย์

fruits=(apple pear plumm peach melon)            
vegetables=(carrot tomato cucumber potatoe onion)

printf "Fruits:\t%s\n" "${fruits[*]}"            
printf "Fruits:\t%s\n" "${fruits[@]}"            
echo + --------------------------------------------- +      
printf "Vegetables:\t%s\n" "${vegetables[*]}"    
printf "Vegetables:\t%s\n" "${vegetables[@]}"    

ดูผลลัพธ์ต่อไปนี้รหัสด้านบน:

Fruits: apple pear plumm peach melon
Fruits: apple
Fruits: pear
Fruits: plumm
Fruits: peach
Fruits: melon
+ --------------------------------------------- +
Vegetables: carrot tomato cucumber potatoe onion
Vegetables: carrot
Vegetables: tomato
Vegetables: cucumber
Vegetables: potatoe
Vegetables: onion

6
การพูดทางวิทยาศาสตร์มะเขือเทศเป็นผลไม้
แรนดี้

1
คุณมีสิทธิ์! "ในพฤกษศาสตร์ผลไม้เป็นโครงสร้างที่มีเมล็ดในพืชออกดอก en.wikipedia.org/wiki/Fruit
stefansson

@ แรนดี้: พูดทางวิทยาศาสตร์ผลไม้ทั้งหมดเป็นผัก (มันเป็นคำพ้องสำหรับ "พืช")
Cris Luengo

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