Shebang เริ่มต้นด้วย `// '?


60

ฉันสับสนเกี่ยวกับการติดตามสคริปต์ ( hello.go)

//usr/bin/env go run $0 $@ ; exit

package main
import "fmt"
func main() {
    fmt.Printf("hello, world\n")
}

มันสามารถดำเนินการ (บน MacOS X 10.9.5)

$ chmod +x hello.go
$ ./hello.go
hello, world

ฉันไม่เคยได้ยินเกี่ยวกับ shebang //มาก่อนเลย และมันก็ยังทำงานได้เมื่อฉันแทรกบรรทัดว่างที่ด้านบนของสคริปต์ เหตุใดสคริปต์นี้จึงทำงาน


//&>/dev/null;x="${0%.*}";[ ! "$x" -ot "$0" ]||(rm -f "$x";cc -o "$x" "$0")&&exec "$x" "$@" ...
ติดตั้ง MONICA ใหม่ - ธนาคารเจเรมี

2
ติดตามความคิดเห็น @ g-man และJörgด้านล่างและตามคำตอบของgilles ( unix.stackexchange.com/a/1919/27616 ) เคล็ดลับนี้ควรใช้///....แทนการใช้งาน//...ร่วมกันได้มากที่สุด!
Olivier Dulac

1
สิ่งนี้จะไม่จัดการข้อโต้แย้ง (หรือตำแหน่งในไดเรกทอรี) อย่างถูกต้องด้วยช่องว่างโดยไม่ต้องใส่เครื่องหมายคำพูดเพิ่มเติม:go run "$0" "$@"
Charles Duffy

คำตอบ:


71

มันไม่ใช่ Shebang มันเป็นเพียงสคริปต์ที่เรียกใช้โดยเชลล์เริ่มต้น เชลล์เรียกใช้งานบรรทัดแรก

//usr/bin/env go run $0 $@ ; exit 

ซึ่งเป็นสาเหตุgoให้ถูกเรียกด้วยชื่อของไฟล์นี้ดังนั้นผลที่ได้คือไฟล์นี้จะทำงานเป็นสคริปต์ไปแล้วเปลือกออกโดยไม่ต้องดูที่ส่วนที่เหลือของไฟล์

แต่ทำไมเริ่มต้นด้วย//แทนที่จะเป็นเพียงแค่/หรือ shebang ที่เหมาะสม#!?

นี่เป็นเพราะไฟล์จะต้องเป็นสคริปต์ที่ถูกต้องไม่เช่นนั้น go ก็จะบ่น ในระหว่างเดินทางอักขระจะ//แสดงความคิดเห็นดังนั้นให้ไปดูบรรทัดแรกเป็นความคิดเห็นและไม่พยายามตีความ #อย่างไรก็ตามตัวละครไม่ได้แสดงความคิดเห็นดังนั้น Shebang ปกติจะส่งผลให้เกิดข้อผิดพลาดเมื่อไปตีความไฟล์

เหตุผลสำหรับไวยากรณ์นี้เป็นเพียงการสร้างไฟล์ที่เป็นทั้งเชลล์สคริปต์และสคริปต์ไปโดยไม่มีใครเหยียบลงบนอีก


10
มันถูกจัดการโดยเคอร์เนลไม่ใช่เชลล์ ดูคำตอบ Gilles เพื่อวิธีการลินุกซ์จับแยกเส้นทางหลาย ๆ (home / ชื่อผู้ใช้ //// /// ไฟล์)
G-Man

3
@HermanTorjussen Feature - การซิงก์ของเส้นทางนั้นถูกนิยามไว้อย่างดีทำให้มีตัวแปรที่มีประโยชน์มากมาย - และด้วยพลังที่ซับซ้อน: /เมื่อส่วนต่อท้ายของเส้นทางถูกกำหนดเป็น/.; เมื่อaไม่ใช่ symlink aจะเหมือนกับa/ที่a/.Thera เป็นกรณีที่พา ธ สามารถเพิ่มได้อีก/โดยไม่มีการเปลี่ยนแปลงในความหมาย เมื่อได้รับเส้นทางซึ่งเป็นที่ยอมรับมีขั้นตอนการทำให้เป็นมาตรฐานที่หดตัวทับอย่างต่อเนื่องเป็นหนึ่ง จริงอยู่มันไม่ใช่ส่วนที่สะอาดของไวยากรณ์อย่างเป็นทางการ
Volker Siegel

13
ที่จริงแล้ว POSIX บอกว่ามีหลายสแลชเหมือนกับสแลชเดียวยกเว้นเมื่อมีสองสแลชที่จุดเริ่มต้นของเส้นทาง เป็นกรณีที่นี่ ในกรณีนั้นการแปลพา ธ นั้นขึ้นอยู่กับการนำไปใช้งาน: "หากชื่อพา ธ เริ่มต้นด้วยอักขระ <slash> ที่ต่อเนื่องกันสองตัวองค์ประกอบแรกที่ตามด้วยอักขระ <slash> ที่นำหน้าอาจถูกตีความในลักษณะที่กำหนดในการนำไปใช้ อักขระ <slash> นำหน้าสองตัวจะถือว่าเป็นอักขระ <slash> เดียว "
Jörg W Mittag

11
ดังนั้นเพื่อให้เป็นอุปกรณ์พกพาควรเขียนแทน///usr/bin/env go run $0 $@ ; exit...
Ruslan

1
@ ดูเปลือกออก แต่ไม่เปิดตัวล่าม go ก่อน ไปคือการพิมพ์สวัสดีโลกไม่ใช่เปลือก
casey

8

มันทำงานเพราะไฟล์ปฏิบัติการเริ่มต้นจะถือว่าเป็น / bin / sh สคริปต์ นั่นคือถ้าคุณไม่ได้ระบุเปลือกเฉพาะใด ๆ - มันคือ #! / bin / sh

// ถูกเพิกเฉยในพา ธ - คุณสามารถพิจารณาได้ว่าอยู่ที่เดียว '/'

ดังนั้นคุณสามารถพิจารณาว่าคุณมีเชลล์สคริปต์ที่มีบรรทัดแรก:

/usr/bin/env go run $0 $@ ; exit

บรรทัดนี้ทำอะไร มันทำงาน 'env' โดยมี paramenters 'go run $ 0 $ @' there 'go' is command และ 'run $ 0 $ @' เป็น args และออกจากสคริปต์หลังจากนั้น $ 0 เป็นชื่อสคริปต์นี้ $ @ เป็นอาร์กิวเมนต์สคริปต์ดั้งเดิม ดังนั้นบรรทัดนี้จะทำงานซึ่งสคริปต์นี้มีอาร์กิวเมนต์

มีรายละเอียดที่น่าสนใจตามที่ระบุไว้ในความคิดเห็นว่าสแลชสองรายการมีการกำหนดการใช้งานและสคริปต์นี้จะกลายเป็น POSIX ที่ถูกต้องหากระบุสแลชสามรายการขึ้นไป อ้างถึงhttp://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.htmlสำหรับรายละเอียดเกี่ยวกับวิธีจัดการสแลชในพา ธ

โปรดทราบด้วยว่ามีความผิดพลาดอีกอย่างในสคริปต์ที่ $ @ ถูกต้องในการใช้ "$ @" แทนเพราะมิฉะนั้นหากมีพารามิเตอร์ใด ๆ ที่มีช่องว่างมันจะถูกแบ่งออกเป็นหลายพารามิเตอร์ ตัวอย่างเช่นคุณไม่สามารถส่งชื่อไฟล์ด้วยช่องว่างได้หากคุณไม่ได้ใช้ "$ @"

เห็นได้ชัดว่าสคริปต์นี้ขึ้นอยู่กับความคิดที่ว่า '//' เท่ากับ '/'


9
"// ถูกเพิกเฉยในพา ธ " - ไม่รับประกันว่า: "หากชื่อพา ธ เริ่มต้นด้วยอักขระ <slash> ที่ต่อเนื่องกันสองตัวองค์ประกอบแรกที่ตามด้วยอักขระ <slash> นำหน้าอาจตีความได้ในลักษณะที่กำหนดตามการนำไปใช้" ( pubs .opengroup.org / onlinepubs / 9699919799 / basedefs / … )
Jörg W Mittag

คำตอบที่น่าสนใจและอัปเดตมาก
gena2x

1
... AFS โดยเฉพาะนำไปใช้ // แตกต่างกันไป แต่มันไม่ใช่เรื่องธรรมดาอีกต่อไป
Charles Duffy

0

สิ่งนี้จะใช้ได้กับ C ++ (และ C หาก C นั้นอนุญาตให้ // สำหรับความคิดเห็น)

//usr/bin/env sh -c 'p=$(expr '"_$0"' : "_\(.*\)\.[^.]*"); make $p > /dev/null && $p'; exit

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