शेल कमांड को सीधे निष्पादित करने के बजाय पायथन के ओएस मॉड्यूल के तरीकों का उपयोग क्यों करें?


157

मैं समझता हूँ कि इस तरह के आदि, फ़ाइलें / निर्देशिका बनाने फ़ाइल विशेषताओं को बदलने के बजाय सिर्फ माध्यम से उन आदेशों को क्रियान्वित करने के रूप में ओएस विशिष्ट कार्यों के क्रियान्वयन की पायथन के पुस्तकालय कार्यों का उपयोग कर के पीछे प्रेरणा क्या है कोशिश कर रहा हूँ os.system()या subprocess.call()?

उदाहरण के लिए, मैं os.chmodऐसा करने के बजाय उपयोग क्यों करना चाहूंगा os.system("chmod...")?

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

मैं केवल यहां सरल एक-लाइन शेल कमांड निष्पादित करने के बारे में बात कर रहा हूं। जब हमें कार्य के निष्पादन पर अधिक नियंत्रण की आवश्यकता होती है, तो मैं समझता हूं कि subprocessमॉड्यूल का उपयोग करना अधिक समझ में आता है, उदाहरण के लिए।


6
आप मूल रूप से सिर पर कील मारते हैं। आपके द्वारा संदर्भित ओएस स्तर के कार्य सामान्य रूप से पर्याप्त हैं कि वे ओएससी सिस्टम के माध्यम से बुलाए जाने के बजाय केवल अपने स्वयं के फ़ंक्शन को वारंट करते हैं।
डेविएडमैन

7
BTW, क्या आपने समय निष्पादन का समय तय किया - os.chmod बनाम os.system ("chmod ...") । मुझे लगता है कि यह आपके प्रश्न के भाग का जवाब देगा।
ज्वालामुखी

61
printजब आप कर सकते थे तो क्यों os.system("echo Hello world!")?
user253751

25
उसी कारण से आपको os.pathमैन्युअल रूप से संभालने के बजाय पथ को संभालने के लिए उपयोग करना चाहिए : यह प्रत्येक ओएस पर काम करता है जहां यह चलता है।
बकुरीउ

51
"सीधे शेल कमांड को निष्पादित करना" वास्तव में कम प्रत्यक्ष है। शेल सिस्टम में निम्न-स्तरीय इंटरफ़ेस os.chmodनहीं है , और chmodशेल को प्रोग्राम को कॉल नहीं करना है। os.system('chmod ...')सी chmodफ़ंक्शन को कॉल करने के लिए किसी अन्य निष्पादन योग्य को कॉल करने के लिए एक स्ट्रिंग की व्याख्या करने के लिए एक शेल का उपयोग करना , जबकि os.chmod(...)सी के लिए बहुत अधिक सीधे जाता है chmod
user2357112

जवाबों:


325
  1. यह तेज़ है , os.systemऔर ऐसी subprocess.callनई प्रक्रियाएँ बनाता है जो इस सरल चीज़ के लिए अनावश्यक है। वास्तव में, os.systemऔर तर्क के subprocess.callसाथ shellआमतौर पर कम से कम दो नई प्रक्रियाएं बनाते हैं: पहला एक शेल है, और दूसरा वह कमांड है जो आप चला रहे हैं (यदि यह शेल निर्मित नहीं है test)।

  2. कुछ कमांड अलग प्रक्रिया में बेकार हैं । उदाहरण के लिए, यदि आप दौड़ते हैं os.spawn("cd dir/"), तो यह बच्चे की प्रक्रिया की वर्तमान कार्यशील निर्देशिका को बदल देगा, लेकिन पायथन प्रक्रिया का नहीं। आपको उसके लिए उपयोग करने की आवश्यकता os.chdirहै।

  3. आपको शेल द्वारा व्याख्या किए गए विशेष वर्णों के बारे में चिंता करने की आवश्यकता नहीं है । os.chmod(path, mode)कोई फर्क नहीं पड़ता कि फ़ाइल नाम क्या है, जबकि कोई भी नाम फ़ाइल नाम की os.spawn("chmod 777 " + path)तरह बुरी तरह से विफल हो जाएगा ; rm -rf ~। (ध्यान दें कि यदि आप subprocess.callबिना shellतर्क के उपयोग करते हैं तो आप इसके आसपास काम कर सकते हैं ।)

  4. आपको फ़ाइल नाम के बारे में चिंता करने की ज़रूरत नहीं है जो एक डैश के साथ शुरू होता हैos.chmod("--quiet", mode)नाम की फ़ाइल की अनुमतियों को बदल देगा --quiet, लेकिन os.spawn("chmod 777 --quiet")असफल हो जाएगा, जैसा --quietकि एक तर्क के रूप में व्याख्या की गई है। यह सच भी है subprocess.call(["chmod", "777", "--quiet"])

  5. आपके पास कम क्रॉस-प्लेटफॉर्म और क्रॉस-शेल चिंताएं हैं, क्योंकि पायथन की मानक लाइब्रेरी आपके लिए इससे निपटने वाली है। क्या आपके सिस्टम में chmodकमांड है? क्या यह स्थापित है? क्या यह उन मापदंडों का समर्थन करता है जो आप समर्थन करने की अपेक्षा करते हैं? osमॉड्यूल जब कि यह संभव नहीं है संभव के रूप में पार मंच और दस्तावेजों के रूप में हो सकता है की कोशिश करेंगे।

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


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

1
@CortAmmon: "निम्न स्तर के" रिश्तेदार है, lsया dirबस के रूप में डेवलपर्स के कुछ प्रकार के लिए बहुत उच्च स्तर होते हैं, bashया cmdया kshया जो कुछ भी शैल आप पसंद करते हैं कर रहे हैं।
सेबेस्टियन मच

1
@phresnel: मैंने इसके बारे में कभी नहीं सोचा था। मेरे लिए, "आपके ओएस के कर्नेल एपीआई पर सीधा कॉल" बहुत निम्न स्तर था। मैं मान रहा हूं कि इस पर एक अलग दृष्टिकोण है जो मुझे अलग कर रहा है क्योंकि मैं (स्वाभाविक रूप से) अपने स्वयं के पूर्वाग्रहों के साथ आ रहा हूं।
कोरट अमोन

5
@CortAmmon: सही है, और lsइससे उच्च स्तर है, क्योंकि यह आपके ओएस के कर्नेल एपीआई पर सीधा कॉल नहीं है। यह एक छोटा (छोटा) अनुप्रयोग है।
स्टीव जेसोप

1
@SteveJessop। मैंने "निम्न स्तर की सामग्री प्राप्त करना" कहा। मैं सोच नहीं कर रहा हूँ lsया dirलेकिन opendir()/readdir()(linux एपीआई) या FindFirstFile()/FindNextFile()(Windows API) या File.listFiles(जावा एपीआई) या Directory.GetFiles()(सी #)। ये सभी OS के सीधे संपर्क में हैं। कुछ एक रजिस्टर में एक नंबर धकेलने और int 13hकर्नेल मोड को ट्रिगर करने के लिए कॉल करने जितना आसान हो सकता है।
Cort Ammon

133

यह सुरक्षित है। आपको यहां एक विचार देने के लिए एक उदाहरण स्क्रिप्ट है

import os
file = raw_input("Please enter a file: ")
os.system("chmod 777 " + file)

यदि उपयोगकर्ता से इनपुट था test; rm -rf ~तो यह होम डायरेक्टरी को हटा देगा।

यही कारण है कि यह अंतर्निहित फ़ंक्शन का उपयोग करने के लिए सुरक्षित है।

इसलिए आपको सिस्टम के बजाय सबप्रोसेस का इस्तेमाल क्यों करना चाहिए।


26
या इसे देखने का एक और तरीका है, सही पाने के लिए क्या आसान है, पायथन प्रोग्राम लिखना या शेल स्क्रिप्ट लिखने वाले पायथन प्रोग्राम लिखना? :-)
स्टीव जेसप

3
@SteveJessop, मेरा एक सहकर्मी आश्चर्यचकित था कि एक छोटी सी पायथन लिपि जिसकी मदद से मैंने उसे 20 (!) गुना तेज़ तन शैल स्क्रिप्ट लिखने में मदद की। मैंने बताया कि आउटपुट पुनर्निर्देशन सेक्सी लग सकता है - लेकिन यह प्रत्येक पुनरावृत्ति पर फ़ाइल खोलने और बंद करने पर जोर देता है। लेकिन कुछ मुश्किल तरीके से सामान करना पसंद करते हैं - :)
ज्वालामुखी

1
@SteveJessop, यह एक ट्रिक सवाल है - आप रनटाइम तक नहीं जानते होंगे! :)

60

आदेश osका उपयोग करते समय os.systemया मॉड्यूल पर मॉड्यूल में अजगर के अधिक विशिष्ट तरीकों को प्राथमिकता देने के लिए चार मजबूत मामले हैं subprocess:

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

अतिरेक ( अनावश्यक कोड देखें ):

आप वास्तव में एक निरर्थक "मध्यम-पुरुष" को अंतिम रूप से सिस्टम कॉल ( chmodआपके उदाहरण में) पर लागू कर रहे हैं। यह बीच का आदमी एक नई प्रक्रिया या उप-खोल है।

से os.system:

सब्स्क्रिप्शन में कमांड (एक स्ट्रिंग) निष्पादित करें ...

और subprocessनई प्रक्रियाओं को स्पॉन करने के लिए सिर्फ एक मॉड्यूल है।

आप इन प्रक्रियाओं को पैदा किए बिना क्या कर सकते हैं।

पोर्टेबिलिटी ( स्रोत कोड पोर्टेबिलिटी देखें ):

osमॉड्यूल का उद्देश्य सामान्य ऑपरेटिंग सिस्टम सेवाएं प्रदान करने के लिए है और यह वर्णन शुरू होता है के साथ:

यह मॉड्यूल ऑपरेटिंग सिस्टम पर निर्भर कार्यक्षमता का उपयोग करने का एक पोर्टेबल तरीका प्रदान करता है।

आप os.listdirविंडोज़ और यूनिक्स दोनों पर उपयोग कर सकते हैं । इस कार्यक्षमता का उपयोग करने os.system/ करने की कोशिश subprocessआपको दो कॉल ( ls/ dir) बनाए रखने के लिए मजबूर करेगी और जांच करेगी कि आप किस ऑपरेटिंग सिस्टम पर हैं। यह उतना पोर्टेबल नहीं है और आगे चलकर और भी अधिक निराशा पैदा करेगा (देखें हैंडल आउटपुट )।

कमांड के परिणामों को समझना:

मान लीजिए कि आप फ़ाइलों को एक निर्देशिका में सूचीबद्ध करना चाहते हैं।

यदि आप os.system("ls")/ का उपयोग कर रहे हैं subprocess.call(['ls']), तो आप केवल प्रक्रिया का आउटपुट वापस पा सकते हैं, जो मूल रूप से फ़ाइल नामों के साथ एक बड़ा स्ट्रिंग है।

आप दो फ़ाइलों से नाम में एक जगह के साथ एक फ़ाइल कैसे बता सकते हैं?

यदि आपको फाइलों को सूचीबद्ध करने की कोई अनुमति नहीं है तो क्या होगा?

आपको अजगर की वस्तुओं का डेटा कैसे मैप करना चाहिए?

ये केवल मेरे सिर के ऊपर से होते हैं, और जब इन समस्याओं के समाधान होते हैं - तो फिर से एक समस्या क्यों हल करें जो आपके लिए हल की गई थी?

यह पहले से मौजूद नहीं है और आप के लिए स्वतंत्र रूप से उपलब्ध है एक कार्यान्वयन को दोहराने के द्वारा नहीं दोहराएं खुद को सिद्धांत (अक्सर "DRY" के रूप में माना जाता है) का पालन करने का एक उदाहरण है ।

सुरक्षा:

os.systemऔर subprocessशक्तिशाली हैं। यह अच्छा है जब आपको इस शक्ति की आवश्यकता होती है, लेकिन यह खतरनाक है जब आप नहीं करते हैं। जब आप उपयोग करते हैं os.listdir, तो आप जानते हैं कि यह कुछ और नहीं कर सकता है फिर फ़ाइलों को सूचीबद्ध करें या एक त्रुटि बढ़ाएं। जब आप उपयोग करते हैं os.systemया subprocessउसी व्यवहार को प्राप्त करने के लिए आप संभावित रूप से कुछ ऐसा कर सकते हैं जो आप करने के लिए नहीं थे।

इंजेक्शन सुरक्षा ( शेल इंजेक्शन उदाहरण देखें ) :

यदि आप एक नए कमांड के रूप में उपयोगकर्ता से इनपुट का उपयोग करते हैं तो आपने मूल रूप से उसे एक शेल दिया है। यह बहुत कुछ SQL इंजेक्शन है जो उपयोगकर्ता के लिए DB में एक शेल प्रदान करता है।

एक उदाहरण के रूप में एक आदेश होगा:

# ... read some user input
os.system(user_input + " some continutation")

इनपुट का उपयोग करके किसी भी मनमाने कोड को चलाने के लिए इसका आसानी से फायदा उठाया जा सकता है : NASTY COMMAND;#आखिरकार:

os.system("NASTY COMMAND; # some continuation")

कई ऐसे कमांड हैं जो आपके सिस्टम को खतरे में डाल सकते हैं।


3
मैं कहूंगा 2. मुख्य कारण है।
jaredad7

23

एक साधारण कारण के लिए - जब आप शेल फ़ंक्शन को कॉल करते हैं, तो यह एक उप-शेल बनाता है जो आपके कमांड के मौजूद होने के बाद नष्ट हो जाता है, इसलिए यदि आप किसी शेल में डायरेक्टरी बदलते हैं - तो यह पायथन में आपके वातावरण को प्रभावित नहीं करता है।

इसके अलावा, सब-शेल बनाने में समय लगता है, इसलिए ओएस कमांड का उपयोग सीधे आपके प्रदर्शन को प्रभावित करेगा

संपादित करें

मेरे कुछ समय परीक्षण चल रहे थे:

In [379]: %timeit os.chmod('Documents/recipes.txt', 0755)
10000 loops, best of 3: 215 us per loop

In [380]: %timeit os.system('chmod 0755 Documents/recipes.txt')
100 loops, best of 3: 2.47 ms per loop

In [382]: %timeit call(['chmod', '0755', 'Documents/recipes.txt'])
100 loops, best of 3: 2.93 ms per loop

आंतरिक फ़ंक्शन 10 से अधिक बार तेजी से चलता है

EDIT2

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


किसी भी तरह से यह iPython के साथ किया जाता है? नहीं सोचा था कि आप %सामान्य दुभाषिया का उपयोग करके विशेष कार्यों का उपयोग कर सकते हैं ।
iProgram

@aPyDeveloper, yep, यह iPython था - उबंटू पर। "जादुई" % timeit एक आशीर्वाद है - हालांकि कुछ मामले हैं - ज्यादातर स्ट्रिंग प्रारूपण के साथ - कि यह प्रक्रिया नहीं कर सकता है
ज्वालामुखी

1
या आप एक पायथन स्क्रिप्ट भी बना सकते हैं और फिर time <path to script> टर्मिनल में टाइप कर सकते हैं और यह आपको वास्तविक, उपयोगकर्ता और प्रक्रिया के समय को बताएगा। यदि आपके पास iPython नहीं है और आपके पास Unix कमांड लाइन है।
iProgram

1
@aPyDeveloper, मुझे कड़ी मेहनत करने का कोई कारण नहीं दिखता है - जब मेरे पास मेरी मशीन पर iPython है
ज्वालामुखी

सच! मैंने कहा कि अगर आपके पास iPython नहीं है। :)
iProgram

16

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


1
पायथन मॉड्यूल फ़ंक्शंस नए सबप्रोसेस को भी एक नए सब-इनक्लेव के लिए आमंत्रित करते हैं।
कोडरोक

7
@ कोडरोक बकवास, मॉड्यूल कार्यों को प्रक्रिया में कहा जाता है
dwurf

3
@ कोडरॉक: ओएस मॉड्यूल अंतर्निहित सिस्टम कॉल का उपयोग करता है जो शेल कमांड का उपयोग करता है, यह शेल कमांड का उपयोग नहीं करता है। इसका मतलब है कि ओएस सिस्टम कॉल आमतौर पर सुरक्षित और तेज होती है (शेल स्ट्रिंग की तुलना में कोई स्ट्रिंग पार्सिंग, बू कांटा, कोई निष्पादन नहीं, इसके बजाय यह केवल कर्नेल कॉल है)। ध्यान दें कि ज्यादातर मामलों में, शेल कॉल और सिस्टम कॉल में अक्सर समान या समान नाम होता है, लेकिन अलग से प्रलेखित होता है; शेल कॉल मैन सेक्शन 1 (डिफॉल्ट मैन सेक्शन) में है, जबकि समान रूप से नामित सिस्टम कॉल मैन सेक्शन 2 (जैसे मैन 2 चामॉड) में है।
रेयान

1
@ dwurf, LieRyan: मेरा बुरा! मुझे गलत धारणा थी, ऐसा लगता है। धन्यवाद!
कोडरोक

11

यह कहीं अधिक कुशल है। "शेल" सिर्फ एक और ओएस बाइनरी है जिसमें बहुत सारे सिस्टम कॉल होते हैं। सिर्फ एक ही सिस्टम कॉल के लिए पूरी शेल प्रक्रिया बनाने के ओवरहेड को क्यों उकसाया जाए?

स्थिति और भी बदतर है जब आप os.systemकिसी ऐसी चीज़ के लिए उपयोग करते हैं जो शेल निर्मित नहीं है। आप एक शेल प्रक्रिया शुरू करते हैं जो बदले में एक निष्पादन योग्य शुरू करता है जो तब (दो प्रक्रियाएं दूर) सिस्टम कॉल करता है। कम से कम subprocessएक शेल मध्यस्थ प्रक्रिया की आवश्यकता को हटा दिया होता।

यह पायथन के लिए विशिष्ट नहीं है, यह। systemdएक ही कारण के लिए लिनक्स स्टार्टअप समय के लिए इस तरह के एक सुधार है: यह एक हजार गोले spawning के बजाय आवश्यक सिस्टम कॉल करता है।

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