Shebang นี้เริ่มต้นด้วยเครื่องหมายขีดคั่นคู่ (-) อย่างไร


14

ฉันได้พบ shebang ประเภทต่อไปนี้ในหน้า RosettaCode:

--() { :; }; exec db2 -txf "$0"

มันใช้งานได้สำหรับ Db2 และสิ่งที่คล้ายกันสำหรับ Postgres อย่างไรก็ตามฉันไม่เข้าใจทั้งบรรทัด

ฉันรู้ว่าเส้นประสองครั้งเป็นความคิดเห็นใน SQL และหลังจากนั้นมันเรียกการปฏิบัติการ Db2 ด้วยพารามิเตอร์บางตัวที่ส่งไฟล์ตัวเองเป็นไฟล์ แต่สิ่งที่เกี่ยวกับวงเล็บวงเล็บปีกกาลำไส้ใหญ่และเซมิโคลอนและวิธีสามารถแทนที่ shebang # จริง! ?

https://rosettacode.org/wiki/Multiline_shebang#PostgreSQL

คำตอบ:


18

ที่เกี่ยวข้อง: ล่ามเชลล์คนใดรันสคริปต์ที่ไม่มี shebang

สคริปต์ไม่ได้ shebang / hashbang / สายเพียงเพราะรีบคู่ไม่ได้#!#!

อย่างไรก็ตามสคริปต์ที่จะได้รับการดำเนินการโดยเชลล์ (ดูคำถามและคำตอบเชื่อมโยงดังกล่าว) และในเปลือกว่าถ้า-เป็นตัวละครที่ถูกต้องในชื่อฟังก์ชันสายประกาศฟังก์ชั่นเปลือกที่เรียก--ว่าไม่ทำอะไรเลย (ดีมันวิ่ง:, ซึ่งไม่ทำอะไรเลย ) และสิ่งที่ไม่เคยเรียก

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

-- () {
  :
}

วัตถุประสงค์เพียงอย่างเดียวของการกำหนดฟังก์ชั่นคือการมีบรรทัดที่ถูกต้องในเชลล์สคริปต์และในเวลาเดียวกันคำสั่ง SQL ที่ถูกต้อง (ความคิดเห็น) การจัดเรียงของรหัสนี้เรียกว่าพูดได้หลายภาษา

หลังจากประกาศฟังก์ชั่น bogus เชลล์สคริปต์เมื่อดำเนินการโดยล่ามเชลล์สคริปต์ใช้execเพื่อแทนที่เชลล์ปัจจุบันด้วยกระบวนการที่เกิดจากการทำงานdb2 -txf "$0"ซึ่งจะเหมือนกับการใช้db2 -txfกับชื่อพา ธ ของสคริปต์จากบรรทัดคำสั่ง

เคล็ดลับนี้อาจไม่ทำงานได้อย่างน่าเชื่อถือในระบบที่dashหรือashเปลือกอื่น ๆ ที่ใช้yash, เชลล์เป้าหมายksh88หรือksh93ใช้เป็น/bin/shเพราะเชลล์เหล่านี้ไม่ยอมรับฟังก์ชั่นที่มีชื่อมีเครื่องหมายขีดกลาง

ยังเกี่ยวข้องกับ:


ฉันคิดว่าต่อไปนี้จะใช้งานได้ (ไม่ผ่านการทดสอบจริง ๆ ):

--() { exec db2 -txf "$0"; }; --

@ilkkachu ดีกว่าตอนนี้?
Kusalananda

1
โอ้ใช่! และขอบคุณที่เตือนฉันถึงสิ่งที่เรียกว่า :)
ilkkachu

6

ตามที่ @Kusalananda ได้กล่าวไปแล้วเคล็ดลับนั้นขาดและมันจะไม่ทำงานกับกระสุนทั้งหมด

นี่คือของฉันที่ทำมัน portably:

--/.. 2>/dev/null; exec db2 -txf "$0"

คำสั่งแรกควรล้มเหลวแม้ว่าไฟล์ / ไดเรกทอรีชื่อที่--มีอยู่ในไดเรกทอรีปัจจุบันและข้อผิดพลาดใด ๆ จะถูกปิดโดย2>/dev/null; execเปลือกแล้วจะดำเนินการกับคำสั่งที่สอง


มันยังไม่ได้พกพาจริงๆ ไม่ใช่สคริปต์ที่ถูกต้องและคุณยังคงต้องใช้เชลล์การเรียกเพื่อหลีกเลี่ยงความจริงที่ว่าเคอร์เนลจะปฏิเสธที่จะเรียกใช้สคริปต์และส่งคืนENOEXECหากคุณพยายาม ลองเรียกใช้สคริปต์ภายใต้straceเพื่อดูว่าฉันหมายถึงอะไร
kasperd

@kasperd มันควรจะเป็นแบบพกพาเชลล์ควรรันสคริปต์เป็นเชลล์สคริปต์หากexec()ไม่สามารถใช้งานได้ "หากฟังก์ชั่น execl () ล้มเหลวเนื่องจากข้อผิดพลาดเทียบเท่ากับข้อผิดพลาด [ENOEXEC] เชลล์จะดำเนินการคำสั่งเทียบเท่ากับการเรียกเชลล์ด้วยชื่อคำสั่งเป็นตัวถูกดำเนินการแรก ... " (ดูpubs.opengroup .org / onlinepubs / 9699919799.2018edition / utilities / … )
ilkkachu

@ilkkachu แต่สคริปต์ไม่ได้ถูกเรียกใช้งานจากเชลล์เสมอไป หากคุณพยายามใช้สคริปต์ในบริบทอื่น ๆ ที่การปฏิบัติการจะทำงานได้ก็จะล้มเหลว นอกจากนี้เชลล์ยังไม่เห็นด้วยกับการใช้ล่าม ดังนั้นสคริปต์ของคุณจะทำงานแตกต่างหรือล้มเหลวโดยสิ้นเชิงขึ้นอยู่กับบริบทที่ถูกเรียกจาก
kasperd

@kasperd แน่นอนว่ามันจะไม่ทำงานถ้าคุณexec()โดยตรงจากบางอย่างที่ไม่ใช่เปลือก แต่กรณีนี้จะเป็นเช่นไร? คุณอาจต้องการเรียกใช้สคริปต์จากcronหรือเช่นนั้น แต่ฉันคิดว่ามันจะทำงานทุกอย่างผ่านเชลล์อย่างไรก็ตามถึงแม้ว่าจะไม่ใช่มันก็ง่ายที่จะสะกดออกมาdb2 -txf /path/to/scriptในกรณีนี้เนื่องจากคุณต้องทำเพียงครั้งเดียว การทำงานแบบย่อส่วนใหญ่มีประโยชน์กับเชลล์แบบโต้ตอบ แต่แน่นอนว่าสคริปต์แรปเปอร์แยกต่างหากอาจมีประสิทธิภาพมากกว่า
ilkkachu

1
@kasperd ฉันจะไม่รบกวนคุณกับเอกสารและมาตรฐาน แค่ลองดู! echo 'int main(int c,char**a){execvp(a[1],a+1);}' | cc -include unistd.h -xc -; echo echo yeah > a.sh; chmod 755 a.sh; ./a.out ./a.sh; PATH=`pwd` ./a.out a.sh
ลุงบิลลี่
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.