checkbashisms- वर्तमान शेल को निर्धारित करने का एक तरीका है


18

मेरे में .profile, मैं निम्नलिखित कोड का उपयोग यह सुनिश्चित करने के लिए करता हूं कि बैश-संबंधित उपनाम और फ़ंक्शन केवल खट्टे हैं यदि लॉगिन शेल वास्तव में बैस है :

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

मैं वर्तमान में अपने शेल कॉन्फ़िगरेशन फ़ाइलों, स्क्रिप्ट और फ़ंक्शंस को संस्करण नियंत्रण में रखने की प्रक्रिया में हूं। मैंने हाल ही में शेल स्क्रिप्ट्स से कैज़ुअल बैशीज़ को हटाने की प्रक्रिया शुरू की है, जो बैश-विशिष्ट सुविधाओं से लाभ नहीं उठाते हैं, जैसे, के function funcname()साथ प्रतिस्थापित करना funcname()

मेरी शेल फाइलों के भंडार के लिए, मैंने प्री-कम हुक को कॉन्फ़िगर किया है जो कि रिपॉजिटरी में प्रत्येक फाइल पर checkbashismsडेबियन के डिस्क्रिप्टिव पैकेज से उपयोगिता चलाता shहै ताकि यह सुनिश्चित हो सके कि मैं अनजाने में बैश-विशिष्ट वाक्यविन्यास का परिचय नहीं देता हूं। हालाँकि, यह मेरे लिए एक त्रुटि उत्पन्न करता है .profile:

possible bashism in .profile line 51 ($BASH_SOMETHING):
if [ "${BASH_VERSION:-}" ]; then

मैं सोच रहा था कि क्या कोई तरीका है जो यह जांचने के लिए है कि कोई चेतावनी नहीं चल रही है checkbashisms

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

फिलहाल, मैंने इसे .profileसंसाधित होने से बाहर रखा है checkbashisms; यह एक छोटी फ़ाइल है, इसलिए इसे मैन्युअल रूप से जांचना मुश्किल नहीं है। हालाँकि, इस मुद्दे पर शोध करने के बाद, मैं अभी भी जानना चाहूंगा कि क्या कोई POSIX शिकायत विधि है जो यह निर्धारित करती है कि कौन सा शेल चल रहा है (या कम से कम एक तरीका है जो checkbashismsविफल होने का कारण नहीं है )।


आगे की पृष्ठभूमि / स्पष्टीकरण

संस्करण नियंत्रण के तहत मैं अपने शेल कॉन्फ़िगरेशन फ़ाइलों को डाल रहा हूं, इसका एक कारण यह है कि मैं वर्तमान समय में नियमित रूप से लॉग इन करने वाली सभी प्रणालियों पर अपने वातावरण को कॉन्फ़िगर करने के लिए हूं: साइगविन, उबंटू और सेंटोस (दोनों 5 और 7 दोनों, उपयोगकर्ता के लिए सक्रिय निर्देशिका का उपयोग करके। प्रमाणीकरण)। मैं अक्सर दूरस्थ होस्ट के लिए एक्स विंडोज / डेस्कटॉप वातावरण और एसएसएच के माध्यम से लॉग ऑन करता हूं। हालाँकि, मैं चाहूंगा कि यह भविष्य का प्रमाण हो और सिस्टम की निर्भरता और अन्य साधनों पर कम से कम निर्भरता हो।

मैं checkbashismsअपने शेल से संबंधित फ़ाइलों के सिंटैक्स के लिए एक सरल, स्वचालित स्वच्छता जांच के रूप में उपयोग कर रहा हूं । यह एक आदर्श उपकरण नहीं है, उदाहरण के लिए, मैंने पहले ही इस पर एक पैच लागू कर दिया है ताकि यह command -vमेरी लिपियों के उपयोग के बारे में शिकायत न करे । शोध करते समय, मैंने सीखा है कि कार्यक्रम का वास्तविक उद्देश्य डेबियन नीति का अनुपालन सुनिश्चित करना है, जैसा कि मैं समझता हूं, यह 2008 (या इसके 2013 के संशोधन) के बजाय POSIX 2004 पर आधारित है।


आप जो कर रहे हैं वह पोसिक्स के अनुरूप है जैसा कि कुछ हो सकता है जब पूरा बिंदु अलग-अलग पोसिक्स-अनुरूप वातावरणों पर अलग-अलग तरीके से चलना है। आपका गोमांस चेकबैशिज्म के साथ है।
गाइल्स का SO- दुष्ट होना बंद करें '

और वैसे भी मैंने अपने कॉन्फ़िगरेशन की पोर्टेबिलिटी की जांच करने के लिए कभी भी चेकबेशिज्म का उपयोग नहीं किया है। मैं विभिन्न प्रणालियों पर इसका उपयोग करके इसकी जांच करता हूं।
गिल्स एसओ- बुराई को रोकना '

2
और जिस तरह से, आप यहाँ कर रहे हैं उस विशिष्ट चीज़ के लिए, .bash_profileदोनों स्रोतों को लिखें .profileऔर (सशर्त रूप से) .bashrc
गिल्स एसओ- बुराई को रोकना '

प्रतिक्रिया @Gilles के लिए धन्यवाद। यह विशिष्ट मुद्दे के लिए एक बहुत ही सुंदर समाधान है।
एंथनी जी -

जवाबों:


16

तुम्हारी

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

कोड पूरी तरह से POSIX अनुरूप है और यह जांचने का सबसे अच्छा तरीका है कि आप वर्तमान में चल रहे हैं bash। बेशक $BASH_VERSIONवैरिएबल बैश-स्पेसिफिक है, लेकिन विशेष रूप से आप इसका उपयोग क्यों कर रहे हैं! यह जाँचने के लिए कि आप भाग रहे हैं bash!

ध्यान दें कि $BASH_VERSIONकि क्या निर्धारित किया जाएगा bashके रूप में शुरू हो जाती है bashया sh। एक बार जब आपने यह मान लिया कि आप दौड़ रहे हैं bash, तो आप [ -o posix ]एक संकेतक के रूप में उपयोग कर सकते हैं जो शेल के रूप में लागू किया गया था sh(हालांकि वह विकल्प भी सेट किया गया है जब POSIXLY_CORRECT वातावरण में है या bashजिसे -o posixSHELLOPTS = वातावरण में पॉसिक्स के साथ या साथ बुलाया जाता है। लेकिन उन सभी मामलों में, bashव्यवहार करेंगे जैसे कि कहा जाता है sh)।


एक और वैरिएबल $BASH_VERSIONजिसका आप उपयोग कर सकते हैं और यह कि checkbashismजब तक -xविकल्प पास नहीं होता है, तब तक इसकी शिकायत नहीं करता है $BASH। यह भी विशिष्ट है, bashइसलिए आपको यह निर्धारित करने में सक्षम होना चाहिए कि आप चल रहे हैं bashया नहीं।


मैं यह भी तर्क दूंगा कि यह वास्तव में एक उचित उपयोग नहीं है checkbashismscheckbashismsपोर्टेबल shस्क्रिप्ट लिखने में मदद करने के लिए एक उपकरण है ( shडेबियन नीति में विनिर्देश के अनुसार , पोसिक्स का एक सुपरसेट), यह उन लोगों के लिए गैर-मानक सिंटैक्स की पहचान करने में मदद करता shहै जो सिस्टम पर स्क्रिप्ट लिखने वाले लोगों के लिए एक सहानुभूति है bash

.profileकी व्याख्या विभिन्न गोले द्वारा की जाती है, जिनमें से कई पोसिक्स अनुपालन नहीं हैं। आम तौर पर, आप shअपने लॉगिन शेल के रूप में उपयोग नहीं करते हैं , लेकिन गोले पसंद करते हैं zsh, fishया bashअधिक उन्नत इंटरैक्टिव सुविधाओं के साथ।

bashऔर zsh, जब नहीं कहा जाता है shऔर जब उनके संबंधित प्रोफाइल सत्र फ़ाइल ( .bash_profile, .zprofile) POSIX अनुरूप (विशेष रूप से zsh) नहीं है, लेकिन फिर भी पढ़ा जाता है .profile

तो यह पोसिक्स सिंटैक्स नहीं है जिसे आप चाहते हैं, .profileलेकिन एक सिंटैक्स जो पोसिक्स (के लिए sh) के साथ संगत है , bashऔर zshयदि आप कभी भी उन गोले का उपयोग कर रहे हैं (संभवतः बॉर्न के रूप में बॉर्न शेल भी पढ़ता है .profileलेकिन आमतौर पर लिनक्स-आधारित सिस्टम पर नहीं मिलता है। )।

checkbashismsनिश्चित रूप से आपको बशीशों का पता लगाने में मदद करेगा, लेकिन पोसिक्स सिंटैक्स को इंगित नहीं कर सकता है जो zshया उसके अनुरूप नहीं है bash

यहाँ, यदि आप bash-स्पेशल कोड का उपयोग करना चाहते हैं (जैसे कि bashबग के आस-पास का काम जिससे वह ~/.bashrcइंटरेक्टिव लॉगिन शेल में नहीं पढ़ता है), तो एक बेहतर तरीका यह होगा ~/.bash_profileकि ~/.profileआप अपना आम सत्र रखें, इससे पहले या सोर्सिंग के बाद ऐसा करें initialisations)।


checkbashismsउपयोग किए गए चर के कारण यह पास नहीं होता है।
थॉमस डिकी

2
@ThomasDickey, हाँ, लेकिन यह एक ऐसा मामला है जहाँ चेकबेशिज्म रिपोर्ट को अनदेखा किया जाना चाहिए। अब तक दिए गए अन्य सभी समाधान काफी खराब हैं।
स्टीफन चेज़लस

@ स्टीफनचेज़ेलस आप कहते हैं कि अन्य सभी समाधान बदतर हैं। $0इस विशेष मामले के लिए उपयोग करने में क्या गलत होगा ?
एंथनी जी -

2
@AnthonyGeoghegan जो बैश के रूप में shऔर कुछ अन्य शेल के रूप में कहा जाता है के बीच अंतर नहीं करता है sh
गिल्स एसओ- बुराई को रोकना '

यह एक गलत सकारात्मक भी देता है अगर dashया किसी अन्य गैर-बैश शेल को गलत तरीके से बुलाया गया था argv[0] == "bash", जो कि पूरी तरह से कानूनी है, यदि संभव नहीं है।
केविन

17

आमतौर पर कोई $0इस उद्देश्य के लिए उपयोग करता है । जिस साइट पर आपने इसे जोड़ा है, वह इस प्रकार है:

0
   (Zero.) Expands to the name of the shell or shell script.

बहुत आसन! मुझे $0शेल स्क्रिप्ट के नाम का उपयोग करने की इतनी आदत हो गई है कि मैं यह भूल गया कि यह वर्तमान शेल का भी उल्लेख कर सकता है। धन्यवाद!
एंथोनी जी -

1
हमेशा की तरह, इस सम्मेलन का सभी अच्छे व्यवहार वाले कार्यक्रमों द्वारा सम्मान किया जाता है, लेकिन एक दुर्भावनापूर्ण कार्यक्रम execपरिवार से विभिन्न सिस्टम कॉल का उपयोग करके आपके साथ खिलवाड़ कर सकता है क्योंकि वे कॉलिंग प्रोग्राम को तर्क से पारित होने के लिए बाइनरी को स्ट्रिंग से अलग चलाने की पहचान करने की अनुमति देते हैं। 0.
dmckee

यह .profile :) प्यारा
Rob

5

आमतौर पर शेल पर्यावरण चर आपको डिफ़ॉल्ट शेल बताता है। आपको मैन्युअल रूप से .bashrc फ़ाइल (सत्य नहीं देखें अपडेट bellow) को मैन्युअल रूप से स्रोत करने की आवश्यकता नहीं है, बैश को स्वचालित रूप से यह सुनिश्चित करना चाहिए कि यह $ HOME निर्देशिका में है।

दूसरा विकल्प कुछ ऐसा करना है:

 ps -o cmd= $$

आपको वर्तमान प्रक्रिया के लिए कमांड (बिना तर्क के, = बिना मान के कॉलम हेडर प्रदर्शित नहीं करेगा) बताएगा। उदाहरण आउटपुट:

 $ps -o cmd= $$
 bash
 $sh
 $ps -o cmd= $$
 sh

अपडेट करें:

मुझे सही साबित होना है! :)

.Bashrc को हमेशा उतारा नहीं जाता जैसा कि टिप्पणियों में उल्लिखित किया गया था और /programming/415403/whats-the-difference-between-bashrc-bash-profile-and-environment

तो आप अपने .bashrc को .bash_profile पर ले जा सकते हैं और देख सकते हैं कि परीक्षण किए बिना काम करता है या नहीं। यदि आपके पास ऊपर परीक्षण नहीं है।


1
.bashrcवास्तव में एक लॉगिन शेल द्वारा खट्टा नहीं है लेकिन .profile(यदि यह मौजूद है) या .bash_profileहैं। SHELLPOSIX द्वारा निर्दिष्ट नहीं किया गया है और दुर्भाग्य से, न तो इसके लिए cmdप्रारूप विकल्प है ps
एंथनी जी -

1
यह वह है जो मैं उपयोग करूंगा, लेकिन यह दुर्भावनापूर्ण हेरफेर के अधीन भी है।
dmckee

ध्यान दें कि जबकि ps -o cmd= $$हर जगह बहुत अधिक काम करना चाहिए, $SHELLचर पूरी तरह से अप्रासंगिक है। यह उपयोगकर्ता का डिफ़ॉल्ट शेल है और इस बात पर कोई असर नहीं पड़ता है कि वर्तमान में कौन सी शेल चल रही है या शेल किस स्क्रिप्ट को चला रहा है।
terdon

2
नहीं वास्तव में कोई नहीं। ~/.profileलॉगिन गोले के रूप में शुरू होने पर कई गोले पढ़े जाएंगे । इसलिए, उदाहरण के लिए, आपका $SHELLहो सकता है cshऔर आप चलाते हैं bash -l। यह एक लॉगिन शेल के रूप में बैश करना शुरू कर देगा, इसलिए यह पढ़ेगा ~/.profile, लेकिन आपका $SHELLअभी भी इंगित करेगा csh। इसके अलावा, .profileएक और स्क्रिप्ट द्वारा स्पष्ट रूप से sourced किया जा सकता है। चूंकि ओपी अधिकतम मजबूती के लिए जा रहा है, इसलिए सभी तरह के मामलों पर विचार किया जाना चाहिए। किसी भी स्थिति में, $SHELLवर्तमान में चल रहे शेल के बारे में कोई उपयोगी जानकारी प्रदान नहीं करता है।
terdon

2
FWIW, मैं भी सही खड़ा हूं - SHELLPOSIX द्वारा निर्दिष्ट नहीं किए जाने के बारे में : pubs.opengroup.org/onlinepubs/9699919799/basedefs/…
एंथनी जी -

4

प्रश्न उपयोगकर्ता के लॉगिन शेल के साथ-साथ वर्तमान शेल को भी अपील करने के लिए कहता है checkbashisms। यदि इसका अर्थ वह शेल है जिस पर उपयोगकर्ता लॉग इन करता है, तो मैं उसी का उपयोग करूँगा /etc/passwd, जैसे;

MY_UID=$(id -u)
MYSHELL=$(awk -F: '$3 == '$MY_UID'{ print $7; }' </etc/passwd )

उपयोगकर्ता निश्चित रूप से लॉग इन करने के बाद एक नया शेल शुरू कर सकता है। बेशक, अगर एक बैश है और दूसरा नहीं है, तो बैश के पर्यावरण चर के परीक्षण मदद नहीं कर सकते हैं।

कुछ getentकेवल passwdफ़ाइल के बजाय उपयोग करना चाहते हैं (लेकिन यह प्रश्न के दायरे में नहीं होगा)।

LDAP के बारे में टिप्पणी के आधार पर, और lognameइस वैकल्पिक रूप के लिए सुझाव का उपयोग किया जा सकता है:

MY_NAME=$(logname)
MYSHELL=$(getent passwd | awk -F: '$1 ~ /^'$MY_NAME'$/ {print $7;}' )

इसका परीक्षण करते समय, मैंने देखा कि lognameइसका इनपुट पुनर्निर्देशित नहीं है (इसलिए मैंने अभिव्यक्ति को छोड़ दिया)। एक त्वरित चेक शो getentको वर्णित प्लेटफार्मों पर काम करना चाहिए (हालांकि मूल प्रश्न में प्रदान किया जाना चाहिए):


1
उपयोगकर्ता डेटाबेस मानकर / etc / passwd (LDAP / NIS / mysql ... नहीं) और प्रति उपयोगकर्ता नाम केवल एक उपयोगकर्ता नाम है। (के खिलाफ पहले कॉलम की जांच करना बेहतर होगा $(logname))।
स्टीफन चेज़लस

iirc, POSIX आवश्यक उपयोगिता को परिभाषित नहीं करता है (या मैंने अपने उत्तर में इसका इस्तेमाल किया होगा)। उपयोग करने के लिए idया एक उपयोगकर्ता-परिवर्तनीय चर एक अलग विकल्प है।
थॉमस डिकी

1
ध्यान दें कि मैंने कहा $(logname), नहीं $LOGNAME। उपयोगकर्ता आईडी और लॉगिन शेल दोनों लॉगिन से उपयोग किए गए उपयोगकर्ता नाम से प्राप्त हुए हैं। आप सिस्टम आईडी को छोड़कर उपयोगकर्ता आईडी से लॉगिन शेल पर वापस नहीं आ सकते हैं जहाँ प्रति उपयोगकर्ता आईडी में केवल एक उपयोगकर्ता नाम है। या IOW, उपयोगकर्ता डेटाबेस में प्राथमिक कुंजी उपयोगकर्ता नाम है, यूआईडी नहीं।
स्टीफन चेज़लस

एक अलग दृष्टिकोण से आने वाले उत्तर के लिए @ThomasDickey को धन्यवाद। हालाँकि, यह उससे कहीं अधिक जटिल है जितना मैं सोच रहा था (जैसे कि जिमीज और स्टीफन के उत्तर)। संस्करण नियंत्रण के तहत मैं अपने शेल कॉन्फ़िगरेशन फ़ाइलों को डाल रहा हूं, इसका एक कारण यह है कि मैं उन सभी प्रणालियों पर अपने वातावरण को कॉन्फ़िगर करने के लिए हूं जिन्हें मैं वर्तमान में नियमित आधार पर लॉग इन करता हूं: Cygwin, Ubuntu और CentOS (दोनों 5 और 7, उपयोगकर्ता के लिए सक्रिय निर्देशिका का उपयोग करके। प्रमाणीकरण)। उस कारण से, मैं तर्क को यथासंभव सरल रखना पसंद करता हूं।
एंथनी जी -
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.