เมื่อใดที่ฉันต้องใช้ #! / bin / bash และเมื่อ #! / bin / sh?


104

เมื่อใด#!/bin/bashที่เหมาะสมกว่า#!/bin/shในเชลล์สคริปต์


55
เมื่อคุณใช้bashฟังก์ชั่นและไวยากรณ์มากกว่าshฟังก์ชั่นและไวยากรณ์
Mokubai


3
ถ้ามันช่วยทุกคนฉันสังเกตเห็นว่าvimจะเน้น - bashถ้าสคริปต์ของคุณมี#!/bin/shshebang ฉันจะเปลี่ยนเป็นbashหากสิ่งต่าง ๆ มีขนดกมากพอที่จะเริ่มต้องการคุณลักษณะทุบตี
SeldomNeedy

@SeldomNeedy บางสิ่งที่มันไฮไลต์โดยค่าเริ่มต้นทำงานได้ดีในเปลือก POSIX แม้ว่า $(...)น่ารังเกียจโดยเฉพาะอย่างยิ่ง นอกจากนี้บางคนยังบอบบาง [ <(...)และcmd >& fileไม่ได้รับการเน้นข้อผิดพลาดใด ๆ เช่นพวกเขาไม่มีไฮไลต์พิเศษสำหรับสิ่งที่พวกเขาหมายถึงมีหรือไม่มีg:is_bash]
Random832

@ Random832 ดูเหมือนว่ามีกิจกรรมบางอย่างเกี่ยวกับหัวข้อนี้ในเร็ว ๆ นี้เป็นกลุ่มของปัญหาติดตาม
SeldomNeedy

คำตอบ:


150

ในระยะสั้น:

  • มีหลายเปลือกหอยที่ใช้ซูเปอร์มีข้อกำหนด POSIX ดวลจุดโทษ ในระบบที่ต่างกัน/bin/shอาจเป็นลิงก์ไปยัง ash, bash, dash, ksh, zsh, & c (มันจะเข้ากันได้กับ SH เสมอ - ไม่เคย csh หรือปลา)

  • ตราบใดที่คุณยึดติดกับshคุณสมบัติเท่านั้นคุณสามารถใช้ (และอาจจะควร) #!/bin/shและสคริปต์ควรทำงานได้ดีไม่ว่าจะใช้เชลล์ตัวไหน

  • หากคุณเริ่มใช้คุณสมบัติเฉพาะของ bash (เช่นอาร์เรย์) คุณควรร้องขอ bash เป็นพิเศษ - เนื่องจากแม้ว่า/bin/shจะเรียกใช้ bash ในระบบของคุณอยู่แล้วมันอาจไม่ได้อยู่ในระบบของคนอื่นและสคริปต์ของคุณจะไม่ทำงานที่นั่น (แน่นอนใช้กับ zsh และ ksh.) คุณสามารถใช้shellcheckเพื่อระบุ bashisms

  • แม้ว่าสคริปต์นั้นมีไว้สำหรับการใช้งานส่วนตัวเท่านั้นคุณอาจสังเกตเห็นว่าบาง OS เปลี่ยนแปลง/bin/shในระหว่างการอัพเกรดเช่นบน Debian เคยเป็นทุบตี แต่ภายหลังถูกแทนที่ด้วยเส้นประที่น้อยที่สุด สคริปต์ที่ใช้ bashisms แต่#!/bin/shทันใดนั้นก็พัง

อย่างไรก็ตาม:

  • แม้#!/bin/bashจะไม่ถูกต้องมากนัก ในระบบที่แตกต่างกันทุบตีอาจอาศัยอยู่ใน/usr/binหรือหรือ/usr/pkg/bin/usr/local/bin

  • ตัวเลือกที่น่าเชื่อถือมากขึ้นคือการ#!/usr/bin/env bashใช้ $ PATH (แม้ว่าenvเครื่องมือนั้นจะไม่รับประกันอย่างเข้มงวด แต่/usr/bin/envก็ยังใช้งานได้กับระบบมากกว่าที่เป็น/bin/bashอยู่)


10
คำตอบที่ดี คุณต้องการทำให้เป็น CW หรือไม่?
Mokubai

3
เพียงหมายเหตุถ้า bash ถูกเรียกใช้จาก/bin/shนั้นจะพยายามเลียนแบบshคุณลักษณะต่างๆ (ดูหน้าคน ) ไม่แน่ใจว่าคุณสมบัติเฉพาะของ bash นั้นมีอยู่ในโหมดนี้ envเครื่องมือเป็นเครื่องมือ posix ที่ควรพบในการแจกจ่ายส่วนใหญ่ แต่ฉันไม่แน่ใจเพราะบางคนอาจไม่เคารพ posix
Brice

8
ไม่ในความเป็นจริง POSIX ระบุเป็นพิเศษไม่สามารถสันนิษฐานได้ว่า/bin: " แอปพลิเคชันควรทราบว่า PATH มาตรฐานไปยังเชลล์ไม่สามารถสันนิษฐานได้ว่าเป็น / bin / sh หรือ / usr / bin / sh และควรได้รับการพิจารณา โดยการซักถามของ PATH ที่ส่งคืนโดย getconf PATH ทำให้มั่นใจได้ว่าชื่อพา ธ ที่ส่งคืนนั้นเป็นชื่อพา ธ สัมบูรณ์และไม่ใช่เชลล์ในตัว " ดูคำถามนี้และเฉพาะคำตอบนี้ด้วย
terdon

12
อืมนั่นหมายความว่า POSIX ไม่ได้กำหนดวิธีพกพาสำหรับการ#!ทำงานของสคริปต์
grawity

4
POSIX sh ไม่ใช่ Bourne: เป็นอนุพันธ์ของต้น ksh มากกว่าที่เป็นลูกหลานโดยตรงของ Bourne แยกแยะได้ง่าย: echo foo ^ catปล่อยออกมาfoo ^ catใน POSIX sh และปล่อยเฉพาะfooในบอร์น (ตามที่^เป็นอักขระไพพ์ที่นั่น)
Charles Duffy

18

ใช้ shebang ที่สอดคล้องกับเชลล์ที่คุณใช้พัฒนาและดีบักสคริปต์ของคุณ เช่นถ้าเปลือกเข้าสู่ระบบของคุณและคุณเรียกใช้สคริปต์ของคุณเป็นที่ปฏิบัติการในสถานีของคุณใช้bash #!/bin/bashอย่าเพิ่งคิดว่าเมื่อคุณไม่ได้ใช้อาร์เรย์ (หรือbashคุณสมบัติใด ๆ ที่คุณรับรู้) คุณจะปลอดภัยในการเลือกเปลือกที่คุณชอบ มีความแตกต่างเล็กน้อยระหว่างเชลล์ ( echo, ฟังก์ชั่น, ลูป, คุณตั้งชื่อ) ซึ่งไม่สามารถค้นพบได้หากไม่มีการทดสอบที่เหมาะสม

พิจารณาสิ่งนี้: ถ้าคุณออกไป#!/bin/bashและผู้ใช้ของคุณไม่มีมันพวกเขาจะเห็นข้อความแสดงข้อผิดพลาดที่ชัดเจน

Error: /bin/bash not found

ผู้ใช้ส่วนใหญ่สามารถแก้ไขปัญหานี้ได้ภายในหนึ่งนาทีโดยการติดตั้งแพ็คเกจที่เหมาะสม ในทางกลับกันถ้าคุณแทนที่ shebang ด้วย#!/bin/shและทดสอบบนระบบที่/bin/shมี symlink ให้/bin/bashผู้ใช้ของคุณที่ไม่มีbashปัญหา พวกเขาส่วนใหญ่จะเห็นข้อความผิดพลาดที่เป็นความลับเช่น:

Error in script.sh line 123: error parsing token xyz

อาจใช้เวลาหลายชั่วโมงในการแก้ไขและจะไม่มีเงื่อนงำเกี่ยวกับเชลล์ที่ควรใช้

มีหลายเหตุผลที่คุณต้องการใช้เปลือกที่แตกต่างกันใน Shebang เหตุผลหนึ่งคือเมื่อเชลล์ที่คุณใช้ไม่แพร่หลาย อีกอันหนึ่งก็คือการเพิ่มประสิทธิภาพshซึ่งเร็วกว่าในบางระบบและสคริปต์ของคุณจะเป็นคอขวดของประสิทธิภาพ ในกรณีนี้ให้ทดสอบสคริปต์ของคุณอย่างละเอียดด้วยเชลล์เป้าหมายแล้วเปลี่ยน shebang


@Hastur ฉันไม่ได้รับความคิดเห็นของคุณ Shebang จะกำหนดว่าจะใช้เชลล์ตัวใดในการรันสคริปต์คุณคิดว่าคำตอบของฉันมีความหมายเป็นอย่างอื่นหรือไม่?
Dmitry Grigoryev

1
ลืมมันไปเถอะ ฉันเข้าใจผิดส่วน"ทำไมคุณถึงต้องการใช้" ...
Hastur

6

คุณควรใช้#! /bin/shเท่านั้น

คุณไม่ควรใช้ส่วนขยาย bash (หรือ zsh หรือ fish หรือ ... ) ในเชลล์สคริปต์

คุณควรเท่านั้นที่เคยเขียนสคริปต์เปลือกที่ทำงานร่วมกับใด ๆการดำเนินงานของภาษาเปลือก (รวมทั้งหมด "ยูทิลิตี้โปรแกรม" ที่ไปพร้อมกับเปลือกของตัวเอง) วันนี้คุณอาจใช้POSIX.1-2001 ( ไม่ใช่ -2008) เป็นสิทธิ์สำหรับสิ่งที่เชลล์และยูทิลิตีสามารถใช้งานได้ แต่โปรดทราบว่าวันหนึ่งคุณอาจถูกเรียกให้พอร์ตสคริปต์ของคุณไปยังระบบเดิม (เช่น Solaris หรือ AIX) ซึ่งเชลล์และยูทิลิตีถูกแช่แข็งประมาณปี 1992

อะไรนะ!

ใช่อย่างจริงจัง

นี่คือสิ่งที่: เชลล์เป็นภาษาการเขียนโปรแกรมที่แย่มาก สิ่งเดียวที่มันเกิดขึ้นคือนั่น/bin/shคือตัวแปลสคริปต์เพียงตัวเดียวเท่านั้นที่รับประกันการติดตั้ง Unix ทุกอัน

นี่คือสิ่งอื่น ๆ : ทวนของแกน Perl 5 ล่ามบางคน ( /usr/bin/perl) เป็นมากขึ้นมีแนวโน้มที่จะมีอยู่ในการติดตั้งระบบปฏิบัติการยูนิกซ์สุ่มเลือกกว่า(/(usr|opt)(/(local|sfw|pkg)?)?/bin/bashคือ ภาษาสคริปต์ที่ดีอื่น ๆ (Python, Ruby, node.js เป็นต้น) - ฉันจะใส่ PHP และ Tcl ในประเภทนั้นเมื่อเปรียบเทียบกับเชลล์) นอกจากนี้ยังมีคร่าวๆเช่น bash และ shell ที่ขยายเพิ่มอื่น ๆ

ดังนั้นหากคุณมีตัวเลือกในการเขียนสคริปต์ทุบตีคุณมีตัวเลือกในการใช้ภาษาการเขียนโปรแกรมที่ไม่น่ากลัวแทน

ตอนนี้เชลล์สคริปต์แบบธรรมดาชนิดที่เพิ่งรันโปรแกรมสองสามตัวตามลำดับจากงาน cron หรือบางอย่างไม่มีอะไรผิดปกติที่ปล่อยให้มันเป็นเชลล์สคริปต์ แต่สคริปต์เชลล์แบบง่ายไม่ต้องการอาร์เรย์หรือฟังก์ชั่นหรือ[[แม้กระทั่ง และคุณควรเขียนสคริปต์เชลล์ที่ซับซ้อนเฉพาะเมื่อคุณไม่มีทางเลือกอื่น ตัวอย่างเช่นสคริปต์ Autoconf ยังคงเป็นสคริปต์เชลล์อย่างถูกต้อง แต่สคริปต์เหล่านั้นมีการทำงานในทุกชาติ/bin/shที่เกี่ยวข้องกับโปรแกรมที่มีการกำหนดค่า และนั่นหมายความว่าพวกเขาไม่สามารถใช้ส่วนขยายใด ๆ ได้ คุณอาจจะไม่ได้มีการดูแลเกี่ยวกับกรรมสิทธิ์ Unixes เก่าวันนี้ แต่คุณอาจควรดูแลเกี่ยวกับปัจจุบัน BSDs เปิดแหล่งที่มาบางส่วนที่ไม่ได้ติดตั้งbashbusyboxโดยค่าเริ่มต้นและสภาพแวดล้อมที่ให้คุณเพียงเปลือกที่น้อยที่สุดที่ฝังตัวและ

โดยสรุปเมื่อคุณพบว่าตัวเองต้องการคุณสมบัติที่ไม่มีในภาษาพกพาเชลล์นั่นเป็นสัญญาณว่าสคริปต์นั้นซับซ้อนเกินกว่าที่จะคงเชลล์สคริปต์ไว้ได้ เขียนมันเป็นภาษาที่ดีขึ้นแทน


4
ขออภัยที่มันโง่เล็กน้อย ใช่ถ้าคุณกำลังเขียนบางสิ่งบางอย่างที่จะเป็น i) การกระจายและ ii) shกับสภาพแวดล้อมที่แตกต่างกันคุณควรจะติดขั้นพื้นฐาน อย่างไรก็ตามนั่นเป็นหนทางไกลจากการระบุว่าคุณไม่ควรใช้กระสุนอื่น มีสคริปต์หลายพัน (อาจมากกว่า) เขียนทุกวันและส่วนใหญ่ของสคริปต์ที่จะทำงานบนเครื่องเดียวเท่านั้น คำแนะนำของคุณเหมาะสมกับรหัสการผลิต แต่ไม่ใช่สำหรับงาน "sysdaminy" รายวันที่สคริปต์ส่วนใหญ่เขียนขึ้น ถ้าฉันรู้ว่าสคริปต์ของฉันจะถูกใช้โดยฉันและบนเครื่อง Linux เท่านั้นการทุบตีก็ดี
terdon

1
@terdon จุดคือว่าถ้าคุณมีตัวเลือกในการเขียนสคริปต์ทุบตีแล้วคุณยังมีตัวเลือกในการเขียน Perl (หรืออะไรก็ตาม) สคริปต์และนี่คือมักจะเป็นทางเลือกที่ดีกว่า
zwol

@terdon คำตอบคือไม่งี่เง่าความคิดเห็นของคุณแทนที่จะไร้เดียงสา เชลล์สคริปต์นั้นยอดเยี่ยมในการดีบักเมื่อเทียบกับ Perl และเช่นนั้นซึ่งหนึ่งสามารถใช้ IDE ที่สมบูรณ์แบบด้วยการดีบักแบบกราฟิกและทั้งหมด นอกจากนี้สคริปต์ส่วนใหญ่ที่เขียนทุกวันเพื่อให้สิ่งเล็ก ๆ น้อย ๆ ที่จะทำมีแนวโน้มที่จะเปลี่ยนแปลงและเปลี่ยนแปลงไปซ้ำแล้วซ้ำอีกจะถูกคัดลอกเป็นตัวอย่างไปยังเพื่อนร่วมงานหรือเครือข่ายอื่น ๆ ไม่มีความเสี่ยงที่จะเกิดขึ้น
Thorsten Schöning

@ ThorstenSchöningฉันพูดโง่ไปหน่อย หากนี่คือUnix & Linuxหรือแม้แต่Stack Overflowฉันอาจเห็นด้วย หากเรากำลังพูดถึงแนวปฏิบัติที่ดีที่สุดทั่วไปหรือโปรแกรมเมอร์มืออาชีพแน่นอนว่าควรติดกับ POSIX sh พื้นฐาน อย่างไรก็ตามนี่คือSuper Userเว็บไซต์ที่มุ่งเป้าไปที่ผู้ใช้ปลายทางและบอกผู้ใช้ว่าอย่าใช้ bash หรือ zsh เมื่อเขียนเชลล์สคริปท์
terdon

@terdon ที่จริงแล้วมันมีความสำคัญมากกว่าในความคิดของฉันที่จะกีดกันผู้ใช้จากการเขียนเชลล์สคริปต์ที่ซับซ้อน ผู้เชี่ยวชาญมีระดับทักษะสูงกว่าโดยเฉลี่ย (ดังนั้นพวกเขาจึงมีแนวโน้มที่จะรับมือกับข้อผิดพลาดของการเขียนสคริปต์ที่ซับซ้อนได้) ควรรู้ด้วยความแม่นยำว่าสภาพแวดล้อมใดที่พวกเขาต้องพกพาไปและจ่ายให้ไม่ยอมแพ้ ด้วยความหงุดหงิด
zwol

4

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


2
การโหลดล่ามเปลือกพิเศษจากระบบไฟล์สามารถลบล้างข้อได้เปรียบดังกล่าวและสิ่งใดก็ตามที่จำนวนนาโนวินาที (ซึ่งอยู่ในลำดับความสำคัญเท่ากับวงจรของเครื่องจริง) นับเป็นโดเมนของ C และโปรแกรมเมอร์ภาษาแอสเซมบลี
rackandboneman

Nanoseconds สร้างความแตกต่างในงาน cron เท่านั้นหากคุณมีงานหลายพันล้านงานและ cron จะไม่สามารถจัดการกับสิ่งเหล่านี้ได้มากมาย
Dmitry Grigoryev

1
แม้ว่า mckenzm พูดเกินจริงไปเล็กน้อยก็ไม่ปฏิเสธว่าการมีประสิทธิภาพมากขึ้นนั้นดีกว่า! อย่าวางสายในส่วน "นาโน" (Nanoseconds ไม่นับแม้แต่ใน C เว้นแต่ว่ามันจะวนซ้ำในระบบเรียลไทม์หรือเช่นนั้น!)
jpaugh

1
@jpaugh ยกเว้นว่าคุณกำลังทำงานกับระบบ (ดั้งเดิม) ที่ถือว่าการดำเนินการบางอย่างใช้เวลาอย่างน้อยช่วงเวลาหนึ่ง มันเกิดขึ้น!
JAB

3

หากต้องการความกระชับยิ่งขึ้นให้ใช้shหากการพกพาข้ามระบบส่วนใหญ่มีความสำคัญที่สุดและbashหากคุณต้องการใช้คุณสมบัติบางอย่างเช่นอาร์เรย์หากเวอร์ชันของ bash รองรับ


1
  • sh (สำหรับกรณีส่วนใหญ่) ทุบตีหากต้องการเฉพาะ (หรือ ksh หรืออะไรก็ตาม)

เส้นทางที่ปลอดภัยที่สุด เมื่อรหัสฮาร์ดจะเป็น / usr / bin / shellOfChoiceแต่การประชุมใหม่ฉันพยายามที่จะใช้เสมอตอนนี้เป็น 'สถานที่เริ่มต้น' ผ่านการเปลี่ยนแปลงเส้นทางอาจมีการเปลี่ยนแปลง:

#! / usr / bin / env sh หรือ
#! / usr / bin / env ทุบตี
หรือสำหรับเช่นสคริปต์ Perl
#! / usr / bin / env perl -w

แน่นอนว่าเมื่อคุณมีเหตุผลที่สคริปต์ไม่ควรรับ PATH ใหม่โดยอัตโนมัติจากนั้นให้ทำการเขียนโค้ดแบบฮาร์ดโค้ดต่อไปและ / usr / bin / บางสิ่งบางอย่างควรเป็นพา ธ ที่น่าจะใช้งานมากที่สุด

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