ใช้ #! / bin / sh หรือ #! / bin / bash สำหรับ Ubuntu-OSX ที่ใช้งานร่วมกันได้และใช้งานง่าย & POSIX


18

ฉันรู้ว่าฉันสามารถใช้เป็นบรรทัดแรกของสคริปต์เพื่อเรียกใช้เชลล์ที่ต้องการ

จะ#!/bin/shแนะนำถ้าเข้ากันได้กับทุกระบบยูนิกซ์เป็นข้อกำหนดที่แน่นอน?

ในกรณีของฉันระบบปฏิบัติการเดียวที่ฉันสนใจคือ Ubuntu (Debian) และ OSX จากที่ฉันสามารถใช้#!/bin/bashและมั่นใจได้ว่ามันจะทำงานบนทั้งสองระบบ?
นี่จะทำให้การใช้สคริปต์ที่ง่ายขึ้นและมีไวยากรณ์ที่ทันสมัยและชัดเจนยิ่งขึ้นสำหรับคำสั่งหรือไม่ การใช้#!/bin/shยังเกี่ยวข้องกับการใช้ POSIX หรือไม่


1
น่าจะเป็นที่น่าสังเกตว่า distros หลายคนเริ่มการควบรวมและ/bin /usr/binผลลัพธ์ก็น่าจะดีกว่าที่จะใช้#!/usr/bin/env <shname>เพื่อการพกพาในปัจจุบัน
HalosGhost

คำตอบ:


15

สำหรับผู้เริ่มต้นหากคุณสามารถทำการสันนิษฐานได้ว่า Bash นั้นได้รับการติดตั้งไว้ล่วงหน้า (ซึ่งความรู้ของฉันนั้นเป็นจริงในทุกระบบที่คุณอยู่ในรายการ) ให้ใช้ hashbang ต่อไปนี้เพื่อให้เข้ากันได้:

#!/usr/bin/env bash

จะเรียกนี้สิ่งที่bashเกิดขึ้นจะมีการกำหนดค่าไม่ว่าไม่ว่าจะเป็นในหรือ/bin/usr/local/bin

ในขณะที่อยู่ในระบบส่วนใหญ่ในช่วงกว้าง (รวมถึง AIX, Solaris, รสชาติ BSD หลายรายการ), bashสิ้นสุดในตำแหน่งต่าง ๆ , envมักจะลงเอย/usr/bin/envด้วย อย่างไรก็ตามเคล็ดลับไม่ใช่ของฉัน แต่มาจากผู้แต่งตำราอาหาร Bash

อย่างไรก็ตามใช่ Bash จะช่วยให้คุณใช้คุณสมบัติ "ทันสมัย" บางอย่างที่ทำให้ชีวิตของคุณง่ายขึ้น

ตัวอย่างเช่นเครื่องหมายวงเล็บคู่:

[[ -f "/etc/debian_version" ]] && echo "This is a Debian flavor"

ในขณะที่ในภาษาถิ่นของเปลือกหอยแบบดั้งเดิมคุณจะต้อง:

test -f "/etc/debian_version" && echo "This is a Debian flavor"

แต่สิ่งที่ดีที่สุดเกี่ยวกับวงเล็บคู่คือพวกเขาอนุญาตให้มีการแสดงออกปกติสำหรับการจับคู่ ทุบตีแฮกเกอร์วิกิพีเดียจะให้เทคนิคต่างๆในทิศทางนั้น

คุณยังสามารถใช้นิพจน์ที่ค่อนข้างสะดวกสบายเช่น$((2**10))หรือนิพจน์ทางคณิตศาสตร์อื่น ๆ แบบอินไลน์กับ$((expression))ไวยากรณ์

การใช้ backticks สำหรับ subshells นั้นใช้ได้แม้ว่าจะล้าสมัยไปเล็กน้อย แต่ความสามารถในการซ้อนของ$(command ...)การเรียกใช้จะสะดวกกว่าเพราะคุณไม่ต้องหลบหนีหลาย ๆ อย่างในระดับย่อยต่าง ๆ

สิ่งเหล่านี้คือบางสิ่งที่ Bash มอบให้คุณผ่านทางshไวยากรณ์POSIX ทั่วไปแบบดั้งเดิม

แต่ถ้าคุณต้องการพลังในเชลล์มากกว่า (ไม่ใช่แค่ในสคริปต์) ก็ลองดูzshด้วย


ทุบตีเป็นเครื่องมือที่มีประโยชน์มาก แต่ต้องระวังจะไม่ใช้มันสำหรับการเริ่มต้นการให้บริการที่อาจจะมีความเสี่ยงที่จะเป็นข้อบกพร่องที่สคริปต์ทุบตีเช่นaccess.redhat.com/security/cve/CVE-2014-6271 ติดเพื่อshงานดังกล่าว
Rick-777

1
Rick-777 นั้นมีช่องโหว่มากเกินไปและในความเห็นของฉันความคิดเห็นของคุณคือ FUD หากบริการของระบบทำงานภายใต้การ bash จะไม่มีความเสี่ยงต่อข้อผิดพลาดดังกล่าว มันมีความเสี่ยงต่อข้อผิดพลาดนั้นหากมันทำการแยกกระบวนการ bash ในขณะที่อนุญาตให้ผู้ใช้ทางไกลเข้าถึงตัวแปรสภาพแวดล้อมอย่างน้อยหนึ่งอย่างเช่นใน FastCGI และแม้แต่ใน bash รุ่นที่ไม่ตรงกัน บนระบบที่มีshการเชื่อมโยงกับช่องโหว่จะไม่ถูกลดทอนโดยใช้bash sh
คะแนน _ ต่ำกว่า

11

ใน Debian และ Ubuntu /bin/shคือdashซึ่งเป็นเชลล์ที่สอดคล้องกับ POSIX หากคุณระบุ#!/bin/shคุณต้อง จำกัด ตัวเองเป็นคำสั่ง POSIX ในสคริปต์ของคุณ (ข้อได้เปรียบที่dashเริ่มเร็วกว่าbashเพื่อให้สคริปต์ของคุณสามารถทำงานได้ในเวลาที่น้อยลง)

ในหลาย (ส่วนใหญ่?) ระบบ Linux อื่น ๆ/bin/shคือbashซึ่งเป็นเหตุผลที่สคริปต์มากเขียนด้วย#!/bin/shสาย shebang ของพวกเขาแม้ว่าพวกเขาใช้bashนามสกุล

หากคุณต้องการใช้bashส่วนขยายวิธีการที่ปลอดภัยที่สุดในระบบทั้งหมดคือการระบุ#!/bin/bash; bashวิธีการที่คุณระบุชัดเจนพึ่งพาของคุณบน คุณต้องทำสิ่งนี้กับ Debian และ Ubuntu เป็นโบนัสที่เพิ่มเข้ามาเมื่อเริ่มต้นเป็น/bin/sh bashยกเลิกการเปิดใช้งานส่วนขยาย (ดูคำอธิบายของbashโหมด POSIXสำหรับรายละเอียด); ดังนั้นการระบุเป็นสิ่งจำเป็นที่จะได้รับประโยชน์เต็มที่จาก#!/bin/bashbash

บน OS X /bin/bashสามารถใช้ได้เกินไปและเป็น/bin/sh bashการระบุ#!/bin/bashจะทำงานได้ดีเช่นกัน


5

ใช่ทั้ง OSX และ Linux /bin/bashจะมาพร้อมกับ คุณควรจะปลอดภัยอย่างสมบูรณ์แบบ อย่างไรก็ตามนั่นไม่ใช่ POSIX POSIX เชลล์เป็นระบบ/bin/shส่วนใหญ่ (ทั้งหมด?) และนั่นเป็นวิธีพกพามากที่สุดและเป็นวิธีเดียวที่จะรองรับ POSIX

โปรดทราบว่าในขณะที่ระบบหลาย ๆ ระบบ/bin/shชี้ไปbashที่อื่น ๆ มันสามารถชี้ไปที่เชลล์ที่แตกต่างกัน มันเป็น symlink ไปdashบน Debian และ Ubuntu เช่น นอกจากนี้แม้ว่า/bin/shจะเป็นลิงก์ไปbashยังพฤติกรรมของเชลล์จะเปลี่ยนไปเมื่อมันถูกเรียกว่าเป็นsh(จากการman bashเน้นของฉัน):

หาก bash ถูกเรียกใช้ด้วยชื่อ sh มันจะพยายามเลียนแบบพฤติกรรมการเริ่มต้นของ sh เวอร์ชั่นที่ผ่านมามากที่สุดเท่าที่จะทำได้ในขณะที่สอดคล้องกับมาตรฐาน POSIX เช่นกัน เมื่อเรียกใช้เป็นเชลล์ล็อกอินแบบ interac intertive หรือเชลล์แบบไม่มีการโต้ตอบที่มีตัวเลือก --login อันดับแรกจะพยายามอ่านและเรียกใช้คำสั่งจาก / etc / profile และ ~ / .profile ตามลำดับนั้น --oprofile ตัวเลือกอาจถูกใช้เพื่อยับยั้งพฤติกรรมนี้ เมื่อเรียกใช้เป็นเชลล์แบบโต้ตอบที่มีชื่อ sh, bash จะมองหาตัวแปร ENV, จะขยายค่าของมันถ้าเป็น
กำหนดและใช้ค่าที่ขยายเป็นชื่อของไฟล์เพื่ออ่านและดำเนินการ เนื่องจากเชลล์เรียกใช้โดย sh ไม่ได้พยายามอ่านและเรียกใช้คำสั่งจากไฟล์เริ่มต้นอื่น ๆ อ็อพชัน --rcfile จะไม่มีผลใด ๆ เชลล์ที่ไม่มีการโต้ตอบถูกเรียกใช้ด้วยชื่อ sh จะไม่พยายามอ่านไฟล์เริ่มต้นอื่น ๆ เมื่อเรียกใช้เป็น sh, bash จะเข้าสู่โหมด posix หลังจากอ่านไฟล์เริ่มต้น


2

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

มันแย่กว่านั้นจริงๆ หากคุณต้องการความเข้ากันได้กับระบบ Unix ทั้งหมดซึ่งรวมถึงสิ่งต่าง ๆ เช่น Solaris และ AIX ที่แข็งค่าสภาพแวดล้อมเชลล์ของพวกเขาในปี 1995 ซึ่งหมายความว่าคุณต้องใช้สิ่งต่าง ๆ เช่นsort +Nไวยากรณ์แบบเก่า- ระบบใหม่ที่ลดลง! และมันยังหมายถึงไม่มีฟังก์ชั่นของเชลล์, ไม่มีอาร์เรย์, ไม่[[ ... ]], ไม่${foo#glob}, $(( ... ))สำหรับการคำนวณทางคณิตศาสตร์, อาจจะไม่มีการ$( ... )ทดแทนคำสั่งแบบ, ขีด จำกัด บนและขนาดเล็กที่ไม่มีเอกสารเกี่ยวกับวิธีการป้อนข้อมูลขนาดใหญ่ที่จะได้รับ ...

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


ขอบคุณ ตามที่ระบุไว้เดิม "ในกรณีของฉันระบบปฏิบัติการเดียวที่ฉันสนใจคือ Ubuntu (Debian) และ OSX" นี่เป็นเพียง 2 ระบบที่ฉันเคยใช้ (และฉันใช้มันมาก) ในช่วง 5 ปีที่ผ่านมาดังนั้นนั่นคือ 'ทำไม' ฉันกำลังเขียนเชลล์สคริปต์ที่จะใช้งานได้กับพวกเขาเท่านั้น ฉันไม่ต้องการเลยสำหรับสคริปต์สากลและข้อ จำกัด ที่จะนำเสนอ
Michael Durrant

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