बैश स्क्रिप्ट: सुडो के साथ या बिना बुलाए जाने पर अलग-अलग परिणाम


10

उबंटू में 16.04.3, मेरे पास एक बहुत ही सरल बैश स्क्रिप्ट है:

test.sh

[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $SHELL $0

जब मैं इसे गैर-रूट उपयोगकर्ता के meरूप में या जैसा कहता हूं root, यह अपेक्षा के अनुरूप काम करता है। यदि मैं उपयोग करता हूं sudo ./test.sh, तो यह सिंटैक्स त्रुटि के बारे में शिकायत करता है:

$ ./test.sh
true
me /bin/bash ./test.sh

$ sudo su
# ./test.sh 
true
root /bin/bash ./test.sh

# exit
$ sudo ./test.sh
./test.sh: 1: ./test.sh: [[: not found
false
root /bin/bash ./test.sh

ऐसा किसके कारण हो सकता है? मैं इसे कैसे ठीक कर सकता हूं ताकि meइस स्क्रिप्ट का उपयोग सामान्य रूप से और दोनों के साथ किया जा सके sudo?


3
प्रो टिप: रनिंग का कोई मतलब नहीं हैsudo su । बस sudo -iया sudo -sइसके बजाय भागो ।
टेराडो

@terdon sudo -iस्थान को बदल देता है /rootsudo suया sudo -sनिर्देशिका स्थान नहीं बदलते हैं।
जेम्स न्यूटन

हां, इससे पहले मैंने जो सवाल पूछा था, उसे क्यों पढ़ें। और क्षमा करें, मैंने अपनी पिछली टिप्पणी संपादित कर दी है, मैं उल्लेख करना भूल गया था -s
टेराडो

जवाबों:


20

हर स्क्रिप्ट एक शेबंग से शुरू होती है , इसके बिना आपकी स्क्रिप्ट को शुरू करने वाले शेल को यह पता नहीं होता है कि कौन से दुभाषिया को आपकी स्क्रिप्ट 1 को चलाना चाहिए और sudo ./script.shयहाँ के मामले में - जैसा कि इसके साथ चलना चाहिए sh, जो कि Ubuntu 16.04 में जुड़ा हुआ है dashसशर्त अभिव्यक्ति [[ एक है bashयौगिक आदेश है, तो dashयह कैसे संभाल और त्रुटि आप का सामना करना पड़ा फेंकता को नहीं जानता है।

इसका समाधान यहां जोड़ना है

#!/bin/bash

आपकी स्क्रिप्ट की पहली पंक्ति के रूप में। जब आप इसे स्पष्ट रूप से कहते हैं, तो आपको एक ही परिणाम मिल सकता है sudo bash ./script.sh, लेकिन एक शेबंग जाने का रास्ता है।
यह जांचने के लिए कि आपकी स्क्रिप्ट किस शेल पर चलती है, echo $0इसे जोड़ें । यह wiki.archlinux.org का हवाला देते हुए समान नहीं है :echo $SHELL

शेल में उपयोगकर्ता के पसंदीदा शेल का पथ है। ध्यान दें कि यह आवश्यक रूप से वर्तमान में चल रहा शेल नहीं है, हालांकि बैश स्टार्टअप पर इस चर को सेट करता है।

1: जैसा कि आपने इसके ./test.shसाथ शुरू किया bashथा, बस मान लिया गया है bash, वही sudo suसबशेल के लिए जाता है ।


1
यह भी ध्यान दें कि बैश बैश का उपयोग किए बिना एक स्क्रिप्ट चलाता है, नहीं /bin/sh
मुरु

@ डार्टर्ट जो इसे ठीक करता है। धन्यवाद! मैं एक स्क्रिप्ट के भीतर से कैसे जांच सकता हूं कि कौन सा शेल इसे चला रहा है? ( echo $0मुझे स्क्रिप्ट का नाम देता है: ./test.sh)
जेम्स न्यूटन

@JamesNewton कोई पोर्टेबल तरीका नहीं है, AFAIK, लेकिन आप चेक कर सकते हैं कि कौन से /proc/$$/exeबिंदु हैं। इसके अलावा, आप विभिन्न चर जैसे $BASH_VERSION, $ZSH_VERSIONआदि का परीक्षण कर सकते हैं (लेकिन पानी का छींटा ऐसे किसी भी चर को सेट नहीं करता है)
muru

5

जैसा कि @dessert ने बताया , यहां समस्या यह है कि आपकी स्क्रिप्ट में एक शेल्टिंग लाइन नहीं है । शेबंग के बिना, sudoफ़ाइल का उपयोग करके चलाने का प्रयास करने के लिए डिफ़ॉल्ट होगा /bin/sh। मुझे यह कहीं भी प्रलेखित नहीं मिला, लेकिन मैंने उस sudoस्रोत कोड की जांच करके पुष्टि की जहां मुझे फ़ाइल में निम्नलिखित मिला pathnames.h:

#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif /* _PATH_BSHELL */

इसका अर्थ है "यदि चर _PATH_BSHELLपरिभाषित नहीं है, तो इसे सेट करें /bin/sh"। फिर, configureस्रोत टारबॉल में शामिल स्क्रिप्ट में, हमारे पास है:

for p in "/bin/bash" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do
    if test -f "$p"; then
    found=yes
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5
$as_echo "$p" >&6; }
    cat >>confdefs.h <<EOF
#define _PATH_BSHELL "$p"
EOF

    break
    fi
done

इस पाश के लिए दिखेगा /bin/bash, /usr/bin/sh, /sbin/sh, /usr/sbin/shया /bin/kshऔर फिर सेट _PATH_BSHELLकरने के लिए जो भी पहले मिला था । चूंकि /bin/shसूची में यह पहले था और यह मौजूद है, _PATH_BSHELLपर सेट है /bin/sh। इस सब का नतीजा यह है कि sudoजब तक अन्यथा परिभाषित नहीं किया जाता है तब तक का डिफ़ॉल्ट शेल /bin/sh

इसलिए, उबंटू sudoका उपयोग करके चीजों को चलाने के लिए डिफ़ॉल्ट होगा /bin/sh, जो कि एक सिम्क्लिन है dash, एक न्यूनतम पॉज़िक अनुपालन शेल:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 27  2015 /bin/sh -> dash

[[निर्माण एक बैश सुविधा, यह POSIX मानक से परिभाषित नहीं है जाता है और द्वारा नहीं समझा गया है dash:

$ bash -c '[[ true ]] && echo yes'
yes
$ dash -c '[[ true ]] && echo yes'
dash: 1: [[: not found

विस्तार से, आपके द्वारा किए गए तीन इनवोकेशन में:

  1. ./test.sh

    नहीं sudo; एक शेलबैंग लाइन की अनुपस्थिति में, आपका शेल फ़ाइल को स्वयं निष्पादित करने का प्रयास करेगा। चूंकि आप भाग रहे हैं bash, यह प्रभावी रूप से चलेगा bash ./test.shऔर काम करेगा।

  2. sudo suइसके बाद ./test.sh

    यहां, आप उपयोगकर्ता के लिए एक नया शेल शुरू कर रहे हैं root। यह $SHELLउस उपयोगकर्ता के लिए पर्यावरण चर में जो भी शेल परिभाषित किया गया है, और उबंटू पर, रूट का डिफ़ॉल्ट शेल है bash:

    $ grep root /etc/passwd
    root:x:0:0:root:/root:/bin/bash
  3. sudo ./test.sh

    यहां, आप sudoकमांड को सीधे निष्पादित करने दे रहे हैं। चूंकि इसका डिफ़ॉल्ट शेल /bin/shऊपर बताया गया है, इसलिए यह स्क्रिप्ट को चलाने का कारण बनता है /bin/sh, जो कि है dashऔर यह तब से विफल है जब से dashयह समझ में नहीं आता है [[


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


मैं इसे कहीं भी प्रलेखित नहीं कर सका - मुझे न तो, मैंने सिर्फ यह मान लिया कि यह /bin/shत्रुटि संदेश का उपयोग करेगा - यह और क्या हो सकता है? इस सवाल का खूबसूरती से जवाब दिया गया है कि सूद किस प्रकार का उपयोग करता है · एसओ , यह भी देखें man sudo, अनुभाग कमिटमेंट । बाहर sudoएक मध्यवर्ती खोल का उपयोग नहीं करता है !
मिठाई

1
@ डेज़र्ट हाँ, यह execveसिस्टम कॉल के अपने कार्यान्वयन का उपयोग करता है जो कि चूक करता है sh। और नहीं, मध्यवर्ती गोले अप्रासंगिक हैं, यह उस शेल के बारे में नहीं है जो कमांड को चलाता है बल्कि शेल स्क्रिप्ट को दिए गए शेल स्क्रिप्ट को पढ़ने के लिए उपयोग किया जाता है। तो नहीं, यह एक मध्यवर्ती शेल लॉन्च नहीं करता है, लेकिन इसे अभी भी शेल स्क्रिप्ट के लिए शेल इंटरप्रेटर की आवश्यकता है।
टेर्डन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.