अधिकतम पोर्टेबिलिटी के लिए #! / बिन / श बनाम #! / बिन / बैश


36

मैं आमतौर पर उबंटू LTS सर्वर के साथ काम करता हूं, जिसमें से मैं सिम्लिंक /bin/shको समझता हूं /bin/dash। बहुत से अन्य डिस्ट्रोस के लिए हालांकि सहानुभूति /bin/shहै /bin/bash

इससे मैं समझता हूं कि यदि कोई स्क्रिप्ट #!/bin/shशीर्ष पर उपयोग की जाती है तो क्या वह सभी सर्वरों पर एक ही तरह से नहीं चल सकती है?

जब कोई सर्वर के बीच उन लिपियों की अधिकतम पोर्टेबिलिटी चाहता है, तो स्क्रिप्ट के लिए किस शेल का उपयोग करने का सुझाव दिया गया है?


विभिन्न गोले के बीच मामूली अंतर हैं। यदि पोर्टेबिलिटी आपके लिए सबसे महत्वपूर्ण है तो उपयोग करें #!/bin/shऔर जो मूल शेल प्रदान किया गया है, उसके अलावा किसी और चीज का उपयोग न करें।
थोरबजर्न रेवन एंडरसन

जवाबों:


65

शैल लिपियों के लिए पोर्टेबिलिटी के लगभग चार स्तर हैं (जहाँ तक शबंग रेखा का संबंध है):

  1. अधिकांश पोर्टेबल: एक #!/bin/shशंबिंग का उपयोग करें और पोसिक्स मानक में निर्दिष्ट केवल मूल शेल सिंटैक्स का उपयोग करें । यह बहुत किसी भी POSIX / यूनिक्स / लिनक्स प्रणाली पर काम करना चाहिए। (खैर, सोलारिस 10 को छोड़कर और इससे पहले की वास्तविक विरासत बॉर्न शेल थी, जो पोसिक्स को इतने गैर अनुपालन के रूप में दर्शाती है ।)/bin/sh

  2. दूसरा सबसे पोर्टेबल: एक #!/bin/bash(या #!/usr/bin/env bash) Shebang लाइन का उपयोग करें, और v3 सुविधाओं को मारना छड़ी। यह किसी भी सिस्टम पर काम करेगा जिसमें bash (अपेक्षित स्थान पर) है।

  3. तीसरा सबसे पोर्टेबल: एक #!/bin/bash(या #!/usr/bin/env bash) शेलबैंग लाइन का उपयोग करें, और bash v4 सुविधाओं का उपयोग करें। यह bash v3 (उदाहरण के लिए macOS, जिसे लाइसेंसिंग कारणों से इसका उपयोग करना है) के किसी भी सिस्टम पर विफल हो जाएगा।

  4. कम से कम पोर्टेबल: #!/bin/shशेबंग का उपयोग करें और पोसिक्स शेल सिंटैक्स में बैश एक्सटेंशन का उपयोग करें। यह ऐसे किसी भी सिस्टम पर विफल हो जाएगा जिसमें bash / bin / sh (जैसे हाल के उबंटू संस्करण) के अलावा कुछ भी हो। ऐसा कभी मत करो; यह सिर्फ एक संगतता मुद्दा नहीं है, यह सिर्फ सादा गलत है। दुर्भाग्य से, यह एक त्रुटि है जो बहुत सारे लोग करते हैं।

मेरी सिफारिश: पहले तीन के सबसे रूढ़िवादी का उपयोग करें जो स्क्रिप्ट के लिए आवश्यक सभी शेल विशेषताओं की आपूर्ति करता है। अधिकतम पोर्टेबिलिटी के लिए, विकल्प # 1 का उपयोग करें, लेकिन मेरे अनुभव में कुछ बैश फीचर (जैसे सरणियाँ) पर्याप्त सहायक हैं कि मैं # 2 के साथ जाऊंगा।

सबसे खराब चीज जो आप कर सकते हैं वह है # 4, गलत शेबंग का उपयोग करना। यदि आप सुनिश्चित नहीं हैं कि कौन-सी सुविधाएँ बुनियादी POSIX हैं और जो bash एक्सटेंशन हैं, या तो एक bash shebang (जैसे विकल्प # 2) के साथ रहें, या बहुत मूल शेल (जैसे आपके Ubuntu LTS सर्वर पर डैश) के साथ स्क्रिप्ट का अच्छी तरह से परीक्षण करें। उबंटू विकी के पास देखने के लिए बशीज़ की एक अच्छी सूची है

यूनिक्स और लिनक्स प्रश्न में गोले के बीच के इतिहास और मतभेदों के बारे में कुछ बहुत अच्छी जानकारी है "श को संगत करने का क्या मतलब है?" और Stackoverflow सवाल "श और बैश के बीच अंतर"

इसके अलावा, ध्यान रखें कि शेल एकमात्र ऐसी चीज नहीं है जो विभिन्न प्रणालियों के बीच भिन्न होती है; यदि आप linux के लिए उपयोग किए जाते हैं, तो आप GNU कमांड के लिए उपयोग किए जाते हैं, जिसमें बहुत से गैर-मानक एक्सटेंशन हैं जो आपको अन्य यूनिक्स सिस्टम (जैसे bsd, macOS) पर नहीं मिल सकते हैं। दुर्भाग्य से, यहां कोई सरल नियम नहीं है, आपको बस उन कमांडों के लिए भिन्नता की सीमा को जानना होगा जो आप उपयोग कर रहे हैं।

पोर्टेबिलिटी के संदर्भ में सबसे नास्तिक आदेशों में से एक सबसे बुनियादी है echo:। किसी भी समय आप इसे किसी भी विकल्प (जैसे echo -nया echo -e) के साथ उपयोग करते हैं , या प्रिंट करने के लिए स्ट्रिंग में किसी भी एस्केप (बैकस्लैश) के साथ, विभिन्न संस्करण अलग-अलग काम करेंगे। किसी भी समय आप इसके बाद एक लाइनफीड के बिना एक स्ट्रिंग प्रिंट करना चाहते हैं, या स्ट्रिंग में भागने के साथ, printfइसके बजाय का उपयोग करें (और जानें कि यह कैसे काम करता है - यह इससे अधिक जटिल echoहै)। psआदेश है यह भी एक गड़बड़

एक अन्य सामान्य बात यह है कि हाल ही में / GNUish एक्सटेंशन कमांड विकल्प सिंटैक्स के लिए है: पुराना (मानक) कमांड फॉर्मेट यह है कि कमांड को विकल्पों के साथ (एक डैश के साथ, और प्रत्येक विकल्प एक एकल अक्षर है), उसके बाद आदेश तर्क। हाल के और अक्सर गैर-पोर्टेबल) वेरिएंट में लंबे विकल्प (आमतौर पर पेश किए गए --) शामिल होते हैं, विकल्पों को तर्क के बाद आने देते हैं, और तर्क --से अलग विकल्प का उपयोग करते हैं ।


12
चौथा विकल्प केवल एक गलत विचार है। कृपया इसका उपयोग न करें।
पाबौक

3
@pabouk मैं पूरी तरह से सहमत हूं, इसलिए मैंने इसे स्पष्ट करने के लिए अपने उत्तर को संपादित किया।
गॉर्डन डेविसन

1
आपका पहला बयान थोड़ा भ्रामक है। POSIX मानक शेबंग के बारे में कुछ भी निर्दिष्ट नहीं करता है जिसका उपयोग करके यह अनिर्दिष्ट व्यवहार की ओर जाता है। इसके अलावा, पॉसिक्स निर्दिष्ट नहीं करता है कि पॉज़िक्स शेल कहाँ स्थित होना चाहिए, केवल उसका नाम ( sh), इसलिए /bin/shसही मार्ग होने की गारंटी नहीं है। सबसे पोर्टेबल तब किसी भी शेबंग को निर्दिष्ट करने के लिए नहीं है, या उपयोग किए गए ओएस के लिए शेबंग को अनुकूलित करने के लिए नहीं है।
जूलियाग्रे

2
मैं हाल ही में मेरी एक स्क्रिप्ट के साथ # 4 में गिर गया, और यह पता नहीं लगा सका कि यह काम क्यों नहीं कर रहा है; आखिरकार, एक ही आदेशों ने ठोस रूप से काम किया, और ठीक वही किया जो मैं उन्हें करना चाहता था, जब मैंने उन्हें सीधे शेल में आज़माया। जैसे ही मैं बदल #!/bin/shगया #!/bin/bashहालांकि, स्क्रिप्ट ने पूरी तरह से काम किया। (मेरे बचाव के लिए, वह स्क्रिप्ट समय के साथ विकसित हो गई थी, जिसे वास्तव में केवल श-आइएमएस की जरूरत थी, एक वह जो बैश-जैसे व्यवहार पर निर्भर थी।)
एक CVn

2
@ माइकलकॉर्जलिंग (सच) बॉर्न शेल को लिनक्स वितरण के साथ लगभग कभी भी बंडल नहीं किया गया है और वैसे भी पोसिक्स अनुपालन नहीं है। पोसिक्स मानक शेल को kshबर्ने नहीं, बल्कि व्यवहार से बनाया गया था । एफएचएस के बाद सबसे लिनक्स वितरण क्या होता है जो /bin/shआमतौर पर bashया , पोसिक्स संगतता प्रदान करने के लिए चुने गए शेल के लिए एक प्रतीकात्मक लिंक होता है dash
जुलियाग्रे

5

में ./configureस्क्रिप्ट जो निर्माण के लिए TXR भाषा तैयार करता है, मैं बेहतर पोर्टेबिलिटी के लिए निम्नलिखित प्रस्तावना में लिखा था। यदि #!/bin/shकोई गैर-पॉसिक्स-अनुरूप पुराना बॉर्न शेल है तो भी स्क्रिप्ट बूटस्ट्रैप करेगी । (मैं सोलारिस 10 वीएम पर हर रिलीज का निर्माण करता हूं)।

#!/bin/sh

# use your own variable name instead of txr_shell;
# adjust to taste: search for your favorite shells

if test x$txr_shell = x ; then
  for shell in /bin/bash /usr/bin/bash /usr/xpg4/bin/sh ; do
    if test -x $shell ; then
       txr_shell=$shell
       break
    fi
  done
  if test x$txr_shell = x ; then
    echo "No known POSIX shell found: falling back on /bin/sh, which may not work"
    txr_shell=/bin/sh
  fi
  export txr_shell
  exec $txr_shell $0 ${@+"$@"}
fi

# rest of the script here, executing in upgraded shell

यहाँ पर विचार यह है कि हम उस एक से बेहतर शेल को खोजते हैं, जिस पर हम चल रहे हैं, और उस शेल का उपयोग करके स्क्रिप्ट को फिर से निष्पादित करते हैं। txr_shellवातावरण चर सेट किया गया है, फिर से निष्पादित स्क्रिप्ट जानता है इतना है कि यह फिर से मार डाला पुनरावर्ती उदाहरण है।

(मेरी स्क्रिप्ट में, txr_shellचर को बाद में भी दो उद्देश्यों के लिए उपयोग किया जाता है: सबसे पहले यह स्क्रिप्ट के आउटपुट में एक सूचनात्मक संदेश के हिस्से के रूप में मुद्रित होता है। दूसरे, इसे SHELLचर के रूप में स्थापित किया जाता है Makefile, इसलिए यह makeइसका उपयोग करेगा। शेल भी व्यंजनों को निष्पादित करने के लिए।)

एक सिस्टम पर जहां /bin/shपानी का छींटा है, आप देख सकते हैं कि उपरोक्त तर्क मिल जाएगा /bin/bashऔर उसी के साथ स्क्रिप्ट को फिर से निष्पादित करेगा।

सोलारिस 10 बॉक्स पर, /usr/xpg4/bin/shयदि कोई बैश नहीं पाया जाता है, तो किक करेगा।

प्रस्तावना एक रूढ़िवादी खोल बोली में लिखी जाती है, जिसका उपयोग testफ़ाइल अस्तित्व परीक्षणों के लिए किया जाता है, और ${@+"$@"}कुछ टूटे हुए पुराने गोले को पूरा करने के लिए तर्कों का विस्तार करने की तरकीब (जो कि "$@"अगर हम POSIX अनुरूप खोल में होते तो बस होता )।


xअगर उचित मुहावरे का उपयोग किया जा रहा है तो किसी को हैकरी की आवश्यकता नहीं होगी , क्योंकि उन स्थितियों के लिए जो मुहावरा घिरे हुए हैं अब कई परीक्षणों के साथ -aया -oपरीक्षण परीक्षणों को हटा दिया गया है ।
चार्ल्स डफी

@CharlesDuffy वास्तव में; test x$whateverकि मैं वार्निश में एक प्याज की तरह वहाँ दिखता perpetrating कर रहा हूँ। यदि हम उद्धृत करने के लिए टूटे हुए पुराने शेल पर भरोसा नहीं कर सकते हैं, तो अंतिम ${@+"$@"}प्रयास व्यर्थ है।
कज़

2

बॉर्न शैल भाषा की सभी विविधताएं आधुनिक स्क्रिप्टिंग भाषाओं जैसे पर्ल, पायथन, रूबी, नोड.जेएस और यहां तक ​​कि (यकीनन) Tcl की तुलना में बहुत भयानक हैं। यदि आपको थोड़ा सा जटिल भी करना है, तो आप एक शेल स्क्रिप्ट के बजाय उपरोक्त में से किसी एक का उपयोग करने पर लंबे समय तक खुश रहेंगे।

शेल भाषा का एक और एकमात्र लाभ अभी भी उन नई भाषाओं के ऊपर है कि कुछ कॉलिंग खुद /bin/shको उस चीज़ पर मौजूद होने की गारंटी है जो यूनिक्स होने का अधिकार देता है। हालाँकि, कि कुछ भी POSIX- अनुरूप नहीं हो सकता है; कई विरासत के मालिकाना यूनिक्स ने यूनिक्स 95 (हां, यूनिक्स 95, बीस साल पहले और गिनती) द्वारा मांगे गए परिवर्तनों से पहले लागू की गई भाषा /bin/shऔर डिफ़ॉल्ट पीएटीएच में उपयोगिताओं को फ्रीज कर दिया। वहाँ Unix95 का एक सेट हो सकता है, या यहाँ तक कि POSIX.1-2001 अगर आप भाग्यशाली हैं, एक निर्देशिका में उपकरण नहीं डिफ़ॉल्ट पथ पर (जैसे ), लेकिन वे मौजूद करने के लिए गारंटी नहीं है।/usr/xpg4/bin

हालाँकि, बैश की तुलना में पर्ल की मूल बातें मनमाने ढंग से चयनित यूनिक्स इंस्टॉलेशन पर मौजूद होने की अधिक संभावना है। (पर्ल की मूल बातें "मेरा मतलब /usr/bin/perlहै कि मौजूद है और कुछ है , संभवतः काफी पुराना है, पर्ल 5 का संस्करण, और यदि आप भाग्यशाली हैं कि मॉड्यूल के सेट जो दुभाषिया के उस संस्करण के साथ भेज दिए गए हैं भी उपलब्ध हैं।"

इसलिए:

यदि आप कुछ ऐसा लिख ​​रहे हैं जिसमें हर जगह काम करना है जो कि यूनिक्स होने के लिए है (जैसे कि "कॉन्फ़िगर" स्क्रिप्ट), तो आपको उपयोग करने की आवश्यकता है #! /bin/sh, और आपको किसी भी एक्सटेंशन का उपयोग करने की आवश्यकता नहीं है। आजकल मैं इस परिस्थिति में POSIX.1-2001-आज्ञाकारी खोल लिखूंगा, लेकिन अगर किसी ने जंग खाए हुए लोहे के लिए समर्थन मांगा तो मैं POSIXism बाहर निकालने के लिए तैयार रहूंगा।

लेकिन अगर आप कुछ ऐसा नहीं लिख रहे हैं , जिसमें हर जगह काम करना है, तो जिस क्षण आप किसी भी बशीवाद का उपयोग करने के लिए ललचाते हैं, आपको रुक जाना चाहिए और इसके बजाय एक बेहतर स्क्रिप्टिंग भाषा में पूरी बात को फिर से लिखना चाहिए। आपका भविष्य स्वयं आपको धन्यवाद देगा।

(तो जब है - स्मार्ट टैब-पूरा होने और फैंसी संकेतों प्रदान करने के लिए जैसे ही बैश इंटरैक्टिव वातावरण का विस्तार करने के लिए यह बैश एक्सटेंशन का उपयोग करने उचित पहले के आदेश करने के लिए:: कभी नहीं दूसरा आदेश के लिए?।।)


दूसरे दिन मुझे एक स्क्रिप्ट लिखनी थी, जिसमें कुछ ऐसा था find ... -print0 |while IFS="" read -rd "" file; do ...; done |tar c --null -T -। बशमीज़ ( read -d "") और जीएनयू एक्सटेंशन ( find -print0, tar --null) के बिना इसे सही ढंग से काम करना संभव नहीं होगा । पर्ल में उस रेखा को फिर से लागू करना अधिक लंबा और अनाड़ी होगा। बाशिमों और अन्य गैर-पॉसिक्स एक्सटेंशनों का उपयोग करते समय इस तरह की स्थिति होती है।
मिचू

@michau यह एक-लाइनर के रूप में अर्हता प्राप्त नहीं कर सकता है, जो उन दीर्घवृत्तों में जाता है पर निर्भर करता है, लेकिन मुझे लगता है कि आप " बेहतर स्क्रिप्टिंग भाषा में पूरी बात को फिर से लिखना" नहीं ले रहे हैं, जैसा कि मैं वास्तव में इसका मतलब था। मेरा रास्ता कुछ इस तरह दिखता है perl -MFile::Find -e 'our @tarcmd = ("tar", "c"); find(sub { return unless ...; ...; push @tarcmd, $File::Find::name }, "."); exec @tarcmdकि न केवल आपको किसी भी बशी की ज़रूरत नहीं है, आपको किसी भी GNU टार एक्सटेंशन की ज़रूरत नहीं है। (यदि कमांड लाइन की लंबाई एक चिंता है या आप समानांतर में स्कैन और टार चलाना चाहते हैं, तो आपको ज़रूरत है tar --null -T।)
zwol

बात यह है कि, findमेरे परिदृश्य में 50,000 से अधिक फ़ाइलनाम दिए गए हैं, इसलिए आपकी स्क्रिप्ट तर्क लंबाई सीमा से टकरा सकती है। एक सही कार्यान्वयन जो नॉन-पॉसिक्स एक्सटेंशन का उपयोग नहीं करता है, उसे टार आउटपुट का वृद्धिशील रूप से निर्माण करना होगा, या शायद पुराण का उपयोग करें :: Tar :: Perl कोड में स्ट्रीम। बेशक, यह किया जा सकता है, लेकिन इस मामले में बैश स्क्रिप्ट लिखने के लिए बहुत तेज है और इसमें बॉयलरप्लेट कम है, और इसलिए बग के लिए कम जगह है।
मिचू

BTW, मैं एक तेज और संक्षिप्त तरीके से बैश के बजाय पर्ल का उपयोग कर सकता हूं find ... -print0 |perl -0ne '... print ...' |tar c --null -T -:। लेकिन प्रश्न ये हैं: 1) मैं find -print0और tar --nullवैसे भी उपयोग कर रहा हूं , तो क्या बाश्वाद से बचने की बात है read -d "", जो बिल्कुल उसी तरह का है (अशक्त विभाजक को संभालने के लिए एक GNU एक्सटेंशन जो, पर्ल के विपरीत, किसी दिन POSIX चीज बन सकता है) )? 2) क्या पर्ल वास्तव में बैश से ज्यादा व्यापक है? मैं हाल ही में डॉकर छवियों का उपयोग कर रहा हूं, और उनमें से बहुत से बैश हैं लेकिन कोई पर्ल नहीं है। प्राचीन यूनानियों की तुलना में नई लिपियों के वहां चलने की अधिक संभावना है।
माचू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.