लिनक्स पर शेल (`sh`) से भिन्न में मानक पर रीडायरेक्ट फ़ाइल कैसे करता है?


9

मैंने एक स्क्रिप्ट लिखी है जो उपयोगकर्ताओं को चलते समय स्विच करती है, और मानक में फ़ाइल पुनर्निर्देशन का उपयोग करके इसे निष्पादित करती है। इसलिए user-switch.sh...

#!/bin/bash

whoami
sudo su -l root
whoami

और इसे चलाने से bashमुझे वह व्यवहार मिलता है जिसकी मुझे उम्मीद है

$ bash < user-switch.sh
vagrant
root

हालाँकि, यदि मैं स्क्रिप्ट को चलाता हूं, तो मुझे shअलग आउटपुट मिलता है

$ sh < user-switch.sh 
vagrant
vagrant

bash < user-switch.shसे अलग आउटपुट क्यों दे रहा है sh < user-switch.sh?

टिप्पणियाँ:

  • डेबियन जेसी को चलाने वाले दो अलग-अलग बॉक्स पर होता है

1
एक जवाब नहीं है, लेकिन के बारे में sudo su: unix.stackexchange.com/questions/218169/...
Kusalananda

1
डेबियन पर / बिन / श = पानी का छींटा है? मैं RHEL पर रिप्रजेंट नहीं कर सकता जहाँ / बिन / श = बैश
जेफ स्कॉलर

1
/bin/shपर (मेरी प्रति) डेबियन डैश है, हाँ। मुझे यह भी पता नहीं था कि अब तक क्या था। मैं अब तक बैश के साथ फंस गया हूं।
popedotninja

1
बैश व्यवहार या तो किसी दस्तावेजी अर्थ विज्ञान से काम करने के लिए गारंटी नहीं है।
चार्ल्स डफी

किसी ने आज मुझे बताया कि मैं जिस स्क्रिप्ट का उल्लंघन कर रहा था, वह शब्दार्थ का उल्लंघन करती थी कि कैसे उपयोग करने का इरादा है। इस सवाल के कुछ महान जवाब थे, लेकिन यह इंगित करने के लायक है कि शायद उपयोगकर्ताओं को मध्य स्क्रिप्ट पर स्विच नहीं करना चाहिए। मैंने मूल रूप से user-switch.shजेनकिंस नौकरी में कोशिश की , और यह स्क्रिप्ट निष्पादित हुई। जेनकिंस के बाहर एक ही स्क्रिप्ट चलाने से अलग-अलग परिणाम आए, और मैंने जेनकिंस में जो व्यवहार देखा, उसे प्राप्त करने के लिए पुनर्निर्देशन का सहारा लिया।
popedotninja

जवाबों:


12

एक समान स्क्रिप्ट, बिना sudo, लेकिन समान परिणाम:

$ cat script.sh
#!/bin/bash
sed -e 's/^/--/'
whoami

$ bash < script.sh
--whoami

$ dash < script.sh
itvirta

के साथ bash, बाकी स्क्रिप्ट इनपुट के रूप में जाती है sed, के साथ dash, शेल इसकी व्याख्या करता है।

straceउन पर चल रहा है: dashस्क्रिप्ट का एक ब्लॉक पढ़ता है (आठ केबी यहां, पूरी स्क्रिप्ट को पकड़ने के लिए पर्याप्त से अधिक), और उसके बाद sed:

read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 8192) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...

जिसका अर्थ है कि फ़ाइलहैंड फ़ाइल के अंत में है, और sedकोई इनपुट नहीं देखेगा। शेष भाग को बफ़र किया जा रहा है dash। (यदि स्क्रिप्ट 8 केबी के ब्लॉक आकार से अधिक लंबी थी, तो शेष भाग को पढ़ा जाएगा sed।)

दूसरी ओर, बैश, अंतिम कमांड के अंत में वापस आ जाता है:

read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 36) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
...
lseek(0, -7, SEEK_CUR)                  = 29
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...

यदि इनपुट पाइप से आता है, तो यहां:

$ cat script.sh | bash

रिवाइंडिंग नहीं किया जा सकता है, क्योंकि पाइप और सॉकेट्स खोजने योग्य नहीं हैं। इस मामले में, बैश फैलने से बचने के लिए एक समय में इनपुट एक चरित्र को पढ़ने के लिए वापस गिर जाता है । ( fd_to_buffered_stream()इनinput.c ) प्रत्येक बाइट के लिए एक पूर्ण प्रणाली कॉल करना सिद्धांत रूप में बहुत प्रभावी नहीं है। व्यवहार में, मुझे नहीं लगता कि इस तथ्य की तुलना में रीड्स एक महान ओवरहेड होगा, जो कि ज्यादातर चीजों को खोल देता है जिसमें नई प्रक्रियाएं शामिल हैं।

इसी तरह की स्थिति यह है:

echo -e 'foo\nbar\ndoo' | bash -c 'read a; head -1'

उपधारा को यह सुनिश्चित करना होता है कि readकेवल पहली नई headपंक्ति पढ़ी जाए, ताकि अगली पंक्ति दिखाई दे। (यह dashभी साथ काम करता है।)


दूसरे शब्दों में, बैश स्क्रिप्ट के लिए एक ही स्रोत को पढ़ने के लिए और इससे निष्पादित होने वाले आदेशों का समर्थन करने के लिए अतिरिक्त लंबाई पर जाता है। dashऐसा नहीं करता। और zsh, ksh93डेबियन में पैक इस पर बैश के साथ चलते हैं।


1
सच कहूँ, मैं थोड़ा हैरान हूँ कि काम करता है।
ilkachachu

महान जवाब के लिए धन्यवाद! मैं straceबाद में दोनों कमांड चलाकर आउटपुट की तुलना करूँगा । मैं हालांकि उस दृष्टिकोण का उपयोग करने के लिए नहीं था।
popedotninja

2
हाँ, इस सवाल को पढ़ने पर मेरी प्रतिक्रिया आश्चर्यचकित थी कि यह काम करता है - मैंने इसे कुछ ऐसी चीजों के रूप में दर्ज किया है जो निश्चित रूप से काम नहीं करेगी। मुझे लगता है मैं केवल आधा सही था :)
hobbs

12

शेल मानक इनपुट से स्क्रिप्ट पढ़ रहा है। स्क्रिप्ट के अंदर, आप एक कमांड चलाते हैं जो मानक इनपुट को भी पढ़ना चाहता है। कौन सा इनपुट कहाँ जाना है? आप मज़बूती से नहीं बता सकते

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

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

बैश कमांड निष्पादित करने से पहले स्क्रिप्ट में कमांड के सोर्स कोड के अंत की तलाश करता है। यह कुछ ऐसा नहीं है जिस पर आप भरोसा कर सकते हैं, न केवल इसलिए कि अन्य गोले ऐसा नहीं करते हैं, बल्कि इसलिए भी क्योंकि यह केवल तभी काम करता है जब शेल एक नियमित फ़ाइल से पढ़ रहा हो। यदि शेल एक पाइप (जैसे ssh remote-host.example.com <local-script-file.sh) से पढ़ रहा है, तो जो डेटा पढ़ा गया है वह पढ़ा जाता है और बिना पढ़े नहीं रह सकता।

यदि आप स्क्रिप्ट में एक कमांड में इनपुट पास करना चाहते हैं, तो आपको स्पष्ट रूप से ऐसा करने की आवश्यकता है, आमतौर पर यहां एक दस्तावेज़ के साथ । (यहां एक दस्तावेज़ आमतौर पर मल्टी-लाइन इनपुट के लिए सबसे सुविधाजनक है, लेकिन कोई भी विधि करेगा।) आपके द्वारा लिखा गया कोड केवल कुछ गोले में काम करता है, केवल अगर स्क्रिप्ट को एक नियमित फ़ाइल से शेल में इनपुट के रूप में पारित किया जाता है; यदि आपको उम्मीद है कि दूसरा whoamiइनपुट के रूप में पारित हो जाएगा sudo …, तो फिर से विचार करें, यह ध्यान में रखते हुए कि अधिकतर समय शेल के मानक इनपुट को स्क्रिप्ट पास नहीं किया जाता है।

#!/bin/bash
whoami
sudo su -l root <<'EOF'
whoami
EOF

ध्यान दें कि इस दशक में, आप उपयोग कर सकते हैं sudo -i root। रनिंग sudo suअतीत से एक हैक है।

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