सूडो के साथ बैश स्क्रिप्ट फंक्शन को एक्सेप्ट करना


22

मेरे पास एक स्क्रिप्ट है जो कई अलग-अलग चीजों को करती है, जिनमें से अधिकांश को किसी विशेष विशेषाधिकार की आवश्यकता नहीं है। हालांकि, एक विशिष्ट खंड, जिसे मैंने एक फ़ंक्शन के भीतर समाहित किया है, को रूट विशेषाधिकारों की आवश्यकता है।

मुझे पूरी स्क्रिप्ट को रूट के रूप में चलाने की आवश्यकता नहीं है, और मैं इस फ़ंक्शन को रूट विशेषाधिकारों के साथ स्क्रिप्ट के भीतर से कॉल करने में सक्षम होना चाहता हूं। एक पासवर्ड के लिए संकेत देना यदि आवश्यक हो तो कोई समस्या नहीं है क्योंकि यह वैसे भी ज्यादातर इंटरैक्टिव है। हालांकि, जब मैं उपयोग करने की कोशिश करता sudo functionxहूं, मुझे मिलता है:

sudo: functionx: command not found

जैसा कि मुझे उम्मीद थी, exportफर्क नहीं पड़ा। मैं फ़ंक्शन को स्क्रिप्ट में सीधे निष्पादित करने में सक्षम होना चाहता हूं बजाय इसे तोड़ने और इसे अलग कारणों के लिए एक अलग स्क्रिप्ट के रूप में निष्पादित करने में।

क्या कोई तरीका है जिससे मैं अपने फंक्शन को "सुदो" को बिना एक्स्ट्रेक्ट किए, उपयुक्त डायरेक्टरी ढूंढ कर, और फिर स्टैंड-अलोन स्क्रिप्ट के रूप में निष्पादित कर सकता हूं?

यह फंक्शन एक पेज के बारे में है और इसमें कई स्ट्रिंग्स, कुछ डबल-कोटेड और कुछ सिंगल-कोटेड हैं। यह मुख्य स्क्रिप्ट में कहीं और परिभाषित मेनू फ़ंक्शन पर भी निर्भर है।

मैं केवल sudo के साथ किसी से अपेक्षा करूंगा कि वह फ़ंक्शन को चलाने में सक्षम हो, क्योंकि वह जो कुछ भी करता है वह पासवर्ड बदलता है।


तथ्य यह है कि इसमें कई कार्य शामिल हैं, यह इसे और भी जटिल बनाता है और विफलता का खतरा है। अब आपको ऐसी सभी निर्भरताएँ (और उनकी सभी निर्भरताएँ भी मिल सकती हैं, यदि कोई हो ... हालाँकि, कई स्तरों तक गहरी) सहित कोई भी अन्य फ़ंक्शन जिन्हें मेनू फ़ंक्शन कॉल कर सकते हैं और declareउन्हें भी।
कैस

सहमत, और मुझे बस गोली को काटने और इसे तोड़ने के लिए हो सकता है (और जिस पथ से इसे चलाया गया था, उसे सटीक रूप से निर्धारित करने के लिए मेरी पूरी कोशिश है, साथ ही उम्मीद है कि अंतिम उपयोगकर्ता फ़ाइलों को एक साथ रखता है) अगर कोई बेहतर विकल्प नहीं हैं।
ब्रायकाँ

जवाबों:


19

मैं मानता हूँ कि ऐसा करने का कोई सरल, सहज तरीका नहीं है, और यह थोड़ा हैके है। लेकिन, आप इसे इस तरह से कर सकते हैं:

function hello()
{
    echo "Hello!"
}

# Test that it works.
hello

FUNC=$(declare -f hello)
sudo bash -c "$FUNC; hello"

या अधिक बस:

sudo bash -c "$(declare -f hello); hello"

इससे मेरा काम बनता है:

$ bash --version
GNU bash, version 4.3.42(1)-release (x86_64-apple-darwin14.5.0)
$ hello
Hello!
$
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Hello!

मूल रूप से, declare -fफ़ंक्शन की सामग्री लौटाएगा, जिसे आप तब bash -cइनलाइन पास करते हैं ।

यदि आप बैश के बाहरी उदाहरण से सभी कार्यों को निर्यात करना चाहते हैं, तो बदल FUNC=$(declare -f hello)दें FUNC=$(declare -f)

संपादित करें

उद्धरण के बारे में टिप्पणियों को संबोधित करने के लिए, इस उदाहरण को देखें:

$ hello()
> {
> echo "This 'is a' test."
> }
$ declare -f hello
hello ()
{
    echo "This 'is a' test."
}
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Password:
This 'is a' test.

1
यह केवल दुर्घटना से काम करता है, क्योंकि echo "Hello!"प्रभावी रूप से समान है echo Hello!(यानी डबल-कोट्स इस विशेष इको कमांड के लिए कोई अंतर नहीं है)। कई / अधिकांश अन्य परिस्थितियों में, फ़ंक्शन में दोहरे उद्धरण bash -cकमांड को तोड़ने की संभावना है ।
कैस

1
यह मूल प्रश्न का उत्तर देता है, इसलिए यदि मुझे बेहतर समाधान नहीं मिला तो मैं इसे स्वीकार कर लूंगा। हालाँकि, यह मेरे विशेष फ़ंक्शन को तोड़ता है (मेरा संपादन देखें) क्योंकि यह स्क्रिप्ट में कहीं और परिभाषित कार्यों पर निर्भर है।
ब्रायनकान

1
मैंने आज दोपहर पहले कुछ परीक्षण किया ( bash -xcकेवल के बजाय का उपयोग करके bash -c) और ऐसा लग रहा है कि bashइस स्थिति में चीजों को फिर से उद्धृत करने के लिए पर्याप्त स्मार्ट है, यहां तक ​​कि सिंगल-कोट्स के साथ दोहरे उद्धरणों को बदलने 'और '\''यदि आवश्यक हो तो बदल सकता है। मुझे यकीन है कि कुछ ऐसे मामले होंगे जो इसे संभाल नहीं सकते हैं, लेकिन यह निश्चित रूप से कम से कम सरल और मध्यम जटिल मामलों के लिए काम करता है - उदाहरण के लिए कोशिश करेंfunction hello() { filename="this is a 'filename' with single quotes and spaces" ; echo "$filename" ; } ; FUNC=$(declare -f hello) ; bash -xc "$FUNC ; hello"
cas

4
@cas declare -fफ़ंक्शन परिभाषा को इस तरह से प्रिंट bash -c "$(declare -f)" करता है जिसे बैश द्वारा फिर से पार्स किया जा सकता है, इसलिए सही तरीके से काम करता है (यह मानते हुए कि बाहरी शेल भी बैश है)। आपके द्वारा पोस्ट किया गया उदाहरण इसे सही तरीके से काम करता हुआ दिखाता है - जहां उद्धरण बदले गए थे , ट्रेस में है , क्योंकि शेल सिंटैक्स में निशान प्रिंट करता है, उदाहरण के लिए प्रयास करेंbash -xc 'echo "hello world"'
गाइल्स 'एसओ- बुराई को रोकें'

3
बहुत बढ़िया जवाब। मैंने आपके समाधान को लागू किया - मैं ध्यान दूंगा कि आप स्क्रिप्ट को स्क्रिप्ट के भीतर से ही आयात कर सकते हैं, बशर्ते आप इसे एक सशर्त के भीतर घोंसला दें, जो यह जांचता है कि क्या sudo yourFunctionपाया जा रहा है (अन्यथा आपको पुनरावृत्ति से एक विभाजन त्रुटि मिलती है)
ग्रेफॉक्स

5

"समस्या" वह है sudoजो पर्यावरण को साफ करती है (मुट्ठी भर अनुमत चरों को छोड़कर) और सुरक्षा जोखिमों से बचाने के लिए कुछ चर को पूर्व-निर्धारित सुरक्षित मूल्यों पर सेट करती है। दूसरे शब्दों में, यह वास्तव में कोई समस्या नहीं है। यह एक विशेषता है।

उदाहरण के लिए, यदि आपने PATH को एक पूर्व-निर्धारित मान पर सेट PATH="/path/to/myevildirectory:$PATH"और सेट sudoनहीं किया है, तो कोई भी स्क्रिप्ट जो सभी कमांडों को पूर्ण पथनाम निर्दिष्ट नहीं करती है जो इसे चलाता है (यानी अधिकांश स्क्रिप्ट) /path/to/myevildirectoryकिसी अन्य निर्देशिका से पहले दिखेगा । की तरह रखो आदेशों lsया grepवहाँ में या अन्य आम उपकरणों और आप आसानी से सिस्टम पर की तरह जो कुछ भी आप कर सकते हैं।

सबसे आसान / सबसे अच्छा तरीका फ़ंक्शन को स्क्रिप्ट के रूप में फिर से लिखना है और इसे पथ में कहीं भी सहेजना है (या sudoकमांड लाइन पर स्क्रिप्ट के लिए पूर्ण पथ निर्दिष्ट करना है - जो आपको वैसे भी करने की आवश्यकता होगी जब तक sudoकि आपको अनुमति देने के लिए कॉन्फ़िगर नहीं किया जाता है। किसी भी कमांड को रूट के रूप में चलाने के लिए), और इसके साथ निष्पादन योग्य बनाएंchmod +x /path/to/scriptname.sh

एक खोल समारोह को फिर से लिखने के रूप में एक स्क्रिप्ट सिर्फ एक फाइल करने के लिए समारोह परिभाषा के अंदर आदेशों की बचत के रूप में सरल रूप में है (बिना function ..., {और }लाइनों)।


यह किसी भी तरह से सवाल का जवाब नहीं देता है। वह विशेष रूप से इसे एक स्क्रिप्ट में डालने से बचना चाहते हैं।
विल

1
साथ sudo -Eही पर्यावरण को साफ करने से बचता है।
विल

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

इससे कोई फर्क नहीं पड़ता कि ओपी ने क्या मांगा है या नहीं। अगर वह जो चाहता है वह या तो काम नहीं करेगा या केवल कुछ बेहद असुरक्षित करके काम करने के लिए बनाया जा सकता है, तो उन्हें यह बताने की जरूरत है कि और एक विकल्प प्रदान किया गया है - भले ही विकल्प वे स्पष्ट रूप से कहा गया हो, क्योंकि वे नहीं चाहते (क्योंकि कभी-कभी यह सुरक्षित रूप से करने का एकमात्र या सबसे अच्छा तरीका है)। किसी को यह बताना गैरजिम्मेदार होगा कि अपने पैरों पर बंदूक रखने और ट्रिगर खींचने के संभावित परिणामों के बारे में चेतावनी दिए बिना खुद को पैर में गोली कैसे मारना चाहिए।
कैस

1
@ कैस यह सच है। यह सुरक्षित रूप से नहीं किया जा सकता है कुछ परिस्थितियों में एक स्वीकार्य जवाब है। हालांकि मेरा अंतिम संपादन देखें। मुझे यह जानने के लिए उत्सुक होना चाहिए कि क्या सुरक्षा निहितार्थ पर आपकी राय समान है।
ब्रायनकेन

3

मैंने Sudoऐसा करने के लिए अपना स्वयं का बैश फ़ंक्शन लिखा है, यह फ़ंक्शन और उपनामों को कॉल करने के लिए काम करता है:

function Sudo {
        local firstArg=$1
        if [ $(type -t $firstArg) = function ]
        then
                shift && command sudo bash -c "$(declare -f $firstArg);$firstArg $*"
        elif [ $(type -t $firstArg) = alias ]
        then
                alias sudo='\sudo '
                eval "sudo $@"
        else
                command sudo "$@"
        fi
}

2

आप फ़ंक्शन और उपनाम जोड़ सकते हैं

उदाहरण:

function hello_fn() {
    echo "Hello!" 
}

alias hello='bash -c "$(declare -f hello_fn); hello_fn"' 
alias sudo='sudo '

फिर sudo helloकाम करता है


1

यहाँ विल के उत्तर पर भिन्नता है । इसमें एक अतिरिक्त catप्रक्रिया शामिल है, लेकिन हेरेडोक की सुविधा प्रदान करता है। संक्षेप में यह इस प्रकार है:

f () 
{
    echo ok;
}

cat <<EOS | sudo bash
$(declare -f f)
f
EOS

यदि आप विचार के लिए अधिक भोजन चाहते हैं, तो यह प्रयास करें:

#!/bin/bash

f () 
{ 
    x="a b"; 
    menu "$x"; 
    y="difficult thing"; 
    echo "a $y to parse"; 
}

menu () 
{
    [ "$1" == "a b" ] && 
    echo "here's the menu"; 
}

cat <<EOS | sudo bash
$(declare -f f)
$(declare -f menu)
f
EOS

आउटपुट है:

here's the menu
a difficult thing to pass

यहाँ हमें menuएक प्रश्न के साथ फ़ंक्शन मिला है , जो "मुख्य स्क्रिप्ट में कहीं और परिभाषित किया गया है"। यदि "कहीं और" का अर्थ है कि इसकी परिभाषा पहले से ही इस स्तर पर पढ़ी गई है जब मांग की गई फ़ंक्शन sudoनिष्पादित की जा रही है, तो स्थिति अनुरूप है। लेकिन यह अभी तक पढ़ा नहीं जा सका है। एक और फ़ंक्शन हो सकता है जो अभी तक इसकी परिभाषा को ट्रिगर करेगा। इस मामले declare -f menuमें कुछ अधिक परिष्कृत के साथ प्रतिस्थापित किया जाना चाहिए, या पूरी स्क्रिप्ट को इस तरह से सही किया गया कि menuफ़ंक्शन पहले से ही घोषित हो।


बहुत ही रोचक। मुझे कुछ बिंदु पर इसे आज़माना होगा। और हाँ, menuइस बिंदु से पहले फ़ंक्शन को घोषित किया गया होगा, जैसा fकि एक मेनू से लिया गया है।
ब्रायनकैन

0

यह मानते हुए कि आपकी स्क्रिप्ट या तो (a) स्व-सम्‍मिलित है या (b) इसके लोकेशन के आधार पर इसके कंपोनेंट्स को स्‍त्रोत कर सकती है (बजाय यह याद रखने के कि आपका होम डायरेक्टरी कहां है), आप कुछ इस तरह से कर सकते हैं:

  • $0स्क्रिप्ट के लिए पथनाम का उपयोग करें , sudoकमांड में इसका उपयोग करें , और एक विकल्प के साथ पास करें जो स्क्रिप्ट की जांच करेगा, पासवर्ड अपडेट करने के लिए। जब तक आप पथ में स्क्रिप्ट खोजने पर भरोसा करते हैं (केवल चलाने के बजाय ./myscript), आपको एक पूर्ण पथनाम प्राप्त करना चाहिए $0
  • चूंकि sudoस्क्रिप्ट चलती है, लिपि में इसकी जरूरत उन कार्यों तक होती है।
  • स्क्रिप्ट के शीर्ष पर (बल्कि, फ़ंक्शन की घोषणाओं को पिछले), स्क्रिप्ट इसकी जांच करेगी uidऔर महसूस करेगी कि इसे रूट उपयोगकर्ता के रूप में चलाया गया था , और यह देखते हुए कि इसके पास पासवर्ड अपडेट करने के लिए यह बताने के लिए सेट है, जाओ और करो उस।

लिपियाँ विभिन्न कारणों से स्वयं पर पुनर्विचार कर सकती हैं: विशेषाधिकारों को बदलना उनमें से एक है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.