उपप्रकार में 'खोल = सत्य' का वास्तविक अर्थ


260

मैं subprocessमॉड्यूल के साथ विभिन्न प्रक्रियाओं को बुला रहा हूं । हालांकि, मेरा एक सवाल है।

निम्नलिखित कोड में:

callProcess = subprocess.Popen(['ls', '-l'], shell=True)

तथा

callProcess = subprocess.Popen(['ls', '-l']) # without shell

दोनों कार्य। डॉक्स पढ़ने के बाद, मुझे पता चला कि shell=Trueशेल के माध्यम से कोड निष्पादित करने का मतलब है। तो इसका मतलब है कि अनुपस्थिति में, प्रक्रिया सीधे शुरू की जाती है।

तो मुझे अपने मामले के लिए क्या पसंद करना चाहिए - मुझे एक प्रक्रिया चलाने और उसका आउटपुट प्राप्त करने की आवश्यकता है। मुझे शेल के भीतर या उसके बाहर से कॉल करने से क्या लाभ है।


21
पहले आदेश गलत है: -lकरने के लिए पारित हो जाता है /bin/shके बजाय (शेल) lsकार्यक्रम यूनिक्स अगर परshell=True । स्ट्रिंग तर्क को shell=Trueसूची के बजाय अधिकांश मामलों में उपयोग किया जाना चाहिए ।
18:18

1
"प्रक्रिया सीधे शुरू हो गई है": Wut?
अल्लौरकोड

9
बयान "दोनों काम करते हैं।" उन 2 कॉल के बारे में गलत और भ्रामक है। कॉल अलग तरह से काम करते हैं। बस से स्विच shell=Trueकरने के लिए Falseऔर इसके विपरीत एक त्रुटि है। से डॉक्स : "। खोल = सच, (...) तो आर्ग एक दृश्य है, पहला आइटम निर्दिष्ट कमांड स्ट्रिंग, और किसी भी अतिरिक्त आइटम खोल ही करने के लिए अतिरिक्त तर्क माना जाएगा साथ पर POSIX"। विंडोज पर स्वचालित रूपांतरण है , जो अवांछित हो सकता है।
mbdevpl

यह भी देखें stackoverflow.com/q/59641747/874188
tripleee

जवाबों:


183

शेल के माध्यम से कॉल न करने का लाभ यह है कि आप एक 'मिस्ट्री प्रोग्राम' नहीं ला रहे हैं। POSIX पर, पर्यावरण चर SHELLनियंत्रण करता है जो बाइनरी को "शेल" के रूप में लागू किया जाता है। विंडोज पर, कोई बोर्न शेल वंशज नहीं है, केवल cmd.exe है।

इसलिए शेल को आमंत्रित करना उपयोगकर्ता के चयन के एक कार्यक्रम को आमंत्रित करता है और प्लेटफ़ॉर्म-निर्भर है। सामान्यतया, शेल के माध्यम से इनवोकेशन से बचें।

शेल के माध्यम से इनवॉइस करने से आप शेल के सामान्य तंत्र के अनुसार पर्यावरण चर और फ़ाइल ग्लोब का विस्तार कर सकते हैं। POSIX सिस्टम पर, शेल फ़ाइल ग्लब्स को फ़ाइलों की सूची में विस्तारित करता है। विंडोज, एक फ़ाइल ग्लोब (जैसे, "*। *") पर वैसे भी खोल, द्वारा विस्तार किया जाता है (लेकिन एक कमांड लाइन पर वातावरण चर रहे हैं cmd.exe द्वारा विस्तारित)।

यदि आपको लगता है कि आप पर्यावरण चर विस्तार और फ़ाइल ग्लब्स चाहते हैं, तो ILSनेटवर्क सेवाओं पर 1992-ईश के हमलों पर शोध करें, जो शेल के माध्यम से सबप्रोग्राम इनवोकेशन करता है। उदाहरणों में शामिल विभिन्न sendmailबैकडोर शामिल हैं ILS

संक्षेप में, उपयोग करें shell=False


2
जवाब के लिए धन्यवाद। हालांकि मैं वास्तव में उस स्तर पर नहीं हूं जहां मुझे कारनामों के बारे में चिंता करनी चाहिए, लेकिन मैं समझता हूं कि आप क्या कर रहे हैं।
182 बजे user225312

55
यदि आप शुरुआत में लापरवाह हैं, तो चिंता की कोई भी मात्रा आपको बाद में पकड़ने में मदद नहीं करेगी। ;)
हीथ हुननिकट

क्या होगा यदि आप उपप्रकार की अधिकतम मेमोरी को सीमित करना चाहते हैं? stackoverflow.com/questions/3172470/…
प्रमोद

8
के बारे में बयान $SHELLसही नहीं है। Subprocess.html उद्धृत करने के लिए: "यूनिक्स के साथ shell=True, शेल में चूक होती है /bin/sh।" (नहीं $SHELL)
मार्सिन

1
@ user2428107: हां, यदि आप पर्ल पर बैकटिक इनवोकेशन का उपयोग करते हैं, तो आप शेल इनवोकेशन का उपयोग कर रहे हैं और उन्हीं मुद्दों को खोल रहे हैं। openयदि आप किसी प्रोग्राम को लागू करने और आउटपुट कैप्चर करने के सुरक्षित तरीके चाहते हैं, तो 3+ arg का उपयोग करें ।
शैडो रेंजर

137
>>> import subprocess
>>> subprocess.call('echo $HOME')
Traceback (most recent call last):
...
OSError: [Errno 2] No such file or directory
>>>
>>> subprocess.call('echo $HOME', shell=True)
/user/khong
0

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

स्रोत: उपप्रकार मॉड्यूल


16
पता नहीं क्यों यह चयनित उत्तर नहीं है। अब तक जो वास्तव में सवाल से मेल खाता है
रोड्रिगो लोपेज गुएरा

1
इस बात से सहमत। यह मेरे लिए एक अच्छा उदाहरण है कि शेल = सही अर्थ क्या है।
user389955

2
शेल तर्क को एक सच्चे मान पर सेट करने से उपप्रकार एक मध्यवर्ती शेल प्रक्रिया को फैलाने का कारण बनता है, और इसे कमांड ओह भगवान चलाने के लिए कहता है यह सब बताता है। यह उत्तर क्यों स्वीकार नहीं किया जाता है ??? क्यों?
पूय

मुझे लगता है कि मुद्दा यह है कि कॉल करने के लिए पहला तर्क एक सूची है, एक स्ट्रिंग नहीं है, लेकिन यह त्रुटि देता है यदि शेल गलत है। कमांड को एक सूची में बदलने से यह काम हो जाएगा
लिंकन रान्डल मैकफारलैंड

क्षमा करें मेरी पिछली टिप्पणी मेरे द्वारा किए जाने से पहले की गई थी। स्पष्ट होने के लिए: मैं अक्सर शेल के साथ उपप्रकार का उपयोग देखता हूं = ट्रू और कमांड एक स्ट्रिंग है, उदाहरण के लिए 'ls -l', (मुझे इस त्रुटि से बचने की उम्मीद है) लेकिन सबप्रोसेस एक सूची लेता है (और एक तत्व सूची के रूप में एक स्ट्रिंग) । एक शेल (और उस के साथ सुरक्षा के मुद्दे ) को लागू करने के लिए एक सूची सबप्रोसेस.कॉल का उपयोग करें (['ls', '-l'])
लिंकन रान्डल मैकफारलैंड

42

एक उदाहरण जहां शैल के साथ चीजें गलत हो सकती हैं = यहां दिखाया गया है

>>> from subprocess import call
>>> filename = input("What file would you like to display?\n")
What file would you like to display?
non_existent; rm -rf / # THIS WILL DELETE EVERYTHING IN ROOT PARTITION!!!
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...

यहाँ डॉक्टर की जाँच करें: subprocess.call ()


6
लिंक बहुत उपयोगी है। जैसा कि लिंक में कहा गया है: एक शेल स्रोत से गैर-इनपुट इनपुट को शामिल करने वाले शेल कमांडों को निष्पादित करना एक प्रोग्राम को शेल इंजेक्शन के लिए असुरक्षित बनाता है, एक गंभीर सुरक्षा दोष जिसके परिणामस्वरूप मनमाना कमांड निष्पादन हो सकता है। इस कारण से, शेल = ट्रू का उपयोग उन मामलों में दृढ़ता से हतोत्साहित किया जाता है जहां बाहरी इनपुट से कमांड स्ट्रिंग का निर्माण किया जाता है।
jtuki

39

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

shell=Trueशब्द विभाजन या पैरामीटर विस्तार जैसी विशिष्ट शेल विशेषताओं का उपयोग करने के लिए कभी-कभी सुविधाजनक होता है। हालाँकि, यदि ऐसी सुविधा की आवश्यकता है, तो अन्य मॉड्यूल का उपयोग आपको दिया जाता है (उदाहरण के os.path.expandvars()लिए पैरामीटर विस्तार याshlex शब्द विभाजन के लिए)। इसका मतलब अधिक काम है, लेकिन अन्य समस्याओं से बचा जाता है।

संक्षेप में: shell=Trueहर तरह से बचें ।


16

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

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

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

तुच्छ मामले में, बचने के लिए shell=True, बस प्रतिस्थापित करें

subprocess.Popen("command -with -options 'like this' and\\ an\\ argument", shell=True)

साथ में

subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])

ध्यान दें कि पहला तर्क कैसे पास करने के लिए स्ट्रिंग्स की एक सूची है execvp(), और स्ट्रिंग्स और बैकस्लैश-एस्केप शेल मेटाचैकर्स को कैसे उद्धृत किया जाए , यह आमतौर पर आवश्यक नहीं है (या उपयोगी, या सही)। शायद यह भी देखें कि शेल चर के आसपास कब कोट लपेटें?

एक तरफ के रूप में, आप बहुत बार बचना चाहते हैं Popenयदि subprocessपैकेज में एक सरल रैपर आप क्या चाहते हैं। यदि आपके पास हाल ही में पर्याप्त अजगर है, तो आपको संभवतः उपयोग करना चाहिए subprocess.run

  • इसके साथ check=Trueयदि आप विफल हुआ तो कमांड विफल हो जाएगा।
  • इसके साथ stdout=subprocess.PIPEकमांड का आउटपुट कैप्चर करेगा।
  • थोड़ा अस्पष्ट रूप से, universal_newlines=Trueयह एक उचित यूनिकोड स्ट्रिंग में आउटपुट को डीकोड करेगा (यह सिर्फ bytesसिस्टम एन्कोडिंग में है, अन्यथा पायथन 3 पर)।

यदि नहीं, तो कई कार्यों के लिए, आप check_outputएक कमांड से आउटपुट प्राप्त करना चाहते हैं , जबकि यह जांचना कि यह सफल हुआ है, या check_callअगर कोई आउटपुट इकट्ठा नहीं करना है।

मैं डेविड कॉर्न के एक उद्धरण के साथ बंद करूँगा: "पोर्टेबल शेल स्क्रिप्ट की तुलना में पोर्टेबल शेल लिखना आसान है।" यहां तक ​​कि subprocess.run('echo "$HOME"', shell=True)विंडोज के लिए पोर्टेबल नहीं है।


मुझे लगा कि बोली लैरी वॉल से है लेकिन Google मुझे अन्यथा कहता है।
त्रिकाल

यह उच्च बात है - लेकिन प्रतिस्थापन के लिए कोई तकनीकी सुझाव नहीं है: यहां मैं ओएस-एक्स पर हूं, एक मैक ऐप जिसे मैंने 'ओपन' के माध्यम से लॉन्च करने की कोशिश की है: प्रक्रिया = सबप्रोसेस।पेन ('/ usr / बिन / pgrep') n '+ app_name, शेल = गलत, stdout = subprocess.PIPE, stderr = subprocess.PIPE) app_pid, इरेट = process.communicate () --- लेकिन यह तब तक काम नहीं करता है जब तक कि मैं = True का उपयोग नहीं करूँगा। अब क्या?
मोति श्नोर 12

उत्कृष्ट सवालों के साथ कई सवालों का एक टन है कि कैसे बचें shell=True। आप एक के बारे में है जो लेने के लिए हुआ क्यों बजाय।
ट्रिपल जूल

@MottiShneor प्रतिक्रिया के लिए धन्यवाद; जोड़ा सरल उदाहरण
ट्रिपल जूल

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