कैसे os.system () कॉल से बचने के लिए?


124

Os.system का उपयोग करते समय () यह अक्सर फाइलनाम और अन्य तर्कों से बचने के लिए आवश्यक होता है जो कमांड के मापदंडों के रूप में पारित किए जाते हैं। मैं यह कैसे कर सकता हूँ? अधिमानतः कुछ ऐसा जो कई ऑपरेटिंग सिस्टम / शेल पर काम करेगा, लेकिन विशेष रूप से बैश के लिए।

मैं वर्तमान में निम्नलिखित कार्य कर रहा हूं, लेकिन मुझे यकीन है कि इसके लिए एक लाइब्रेरी फ़ंक्शन होना चाहिए, या कम से कम अधिक सुरुचिपूर्ण / मजबूत / कुशल विकल्प:

def sh_escape(s):
   return s.replace("(","\\(").replace(")","\\)").replace(" ","\\ ")

os.system("cat %s | grep something | sort > %s" 
          % (sh_escape(in_filename), 
             sh_escape(out_filename)))

संपादित करें: मैंने उद्धरणों का उपयोग करने का सरल उत्तर स्वीकार किया है, पता नहीं क्यों मैंने ऐसा नहीं सोचा था; मुझे लगता है क्योंकि मैं विंडोज से आया था, जहां 'और' थोड़ा अलग तरह से व्यवहार करते हैं।

सुरक्षा के बारे में, मैं चिंता को समझता हूं, लेकिन, इस मामले में, मुझे एक त्वरित और आसान समाधान में दिलचस्पी है जो os.system () प्रदान करता है, और तार का स्रोत या तो उपयोगकर्ता-जनित नहीं है या कम से कम एक प्रवेश द्वारा दर्ज किया गया है विश्वसनीय उपयोगकर्ता (मुझे)


1
सुरक्षा के मुद्दे से सावधान! उदाहरण के लिए यदि out_filename foo.txt है; rm -rf / दुर्भावनापूर्ण उपयोगकर्ता शेल द्वारा सीधे व्याख्या की गई अधिक कमांड जोड़ सकता है।
स्टीव ग्यूरी

6
यह os.system के बिना भी उपयोगी है, उन स्थितियों में जहां उपप्रकार भी एक विकल्प नहीं है; जैसे शेल स्क्रिप्ट तैयार करना।

एक आदर्श sh_escapeफ़ंक्शन ;रिक्त स्थान और रिक्त स्थान से बाहर निकलेगा और केवल एक फ़ाइल बनाकर सुरक्षा समस्या को दूर करेगा, जैसे कुछ foo.txt\;\ rm\ -rf\ /
टॉम

लगभग सभी मामलों में, आपको उपप्रकार का उपयोग करना चाहिए, न कि ओएस.सिस्टम। Os.system को कॉल करना केवल एक इंजेक्शन हमले के लिए पूछ रहा है।
एलरयोरकोड

जवाबों:


85

यही है वह जो मेरे द्वारा उपयोग किया जाता है:

def shellquote(s):
    return "'" + s.replace("'", "'\\''") + "'"

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

अद्यतन : यदि आप 3.3 या बाद में पायथन का उपयोग कर रहे हैं, तो अपने स्वयं के रोल करने के बजाय shlex.quote का उपयोग करें।


7
@pixelbeat: यही कारण है कि वह अपने एकल उद्धरणों को बंद कर देता है, एक बची हुई शाब्दिक एकल उद्धरण जोड़ता है, और फिर अपने एकल उद्धरणों को फिर से खोल देता है।
प्रातः

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

10
ध्यान दें कि जब तक आपको शेल विशेषताओं की आवश्यकता नहीं होती है, तब तक आपको संभवतः जेमी के सुझाव का उपयोग करना चाहिए।
लूनाथ

6
इसके समान कुछ अब आधिकारिक तौर पर shlex.quote के रूप में उपलब्ध है ।
Janus Troelsen

3
इस उत्तर में प्रदान किया गया फ़ंक्शन शेल क्विंग का एक बेहतर काम करता है shlexया की तुलना में pipes। उन अजगर मॉड्यूल गलत तरीके से मान लेते हैं कि विशेष वर्ण केवल एक चीज है जिसे उद्धृत करने की आवश्यकता है, जिसका अर्थ है कि शेल कीवर्ड (जैसे time, caseया while) को तब पार्स किया जाएगा जब उस व्यवहार की अपेक्षा नहीं की जाती है। इस कारण से मैं इस उत्तर में एकल-उद्धृत दिनचर्या का उपयोग करने की सलाह दूंगा, क्योंकि यह "चतुर" होने की कोशिश नहीं करता है, इसलिए उन मूर्खतापूर्ण मामलों में नहीं है।
user3035772

157

shlex.quote() अजगर 3 के बाद से आप क्या चाहते हैं।

( pipes.quoteअजगर 2 और अजगर 3 का समर्थन करने के लिए उपयोग करें )


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

3
किसी कारण से, पाइप मॉड्यूल के लिए मानक पुस्तकालय प्रलेखनpipes.quote द्वारा उल्लेख नहीं किया गया है
दिन

1
दोनों अनिर्दिष्ट हैं; command.mkarg3.x में पदावनत और हटा दिया जाता है, जबकि पाइप .quote बने रहे।
बेनी चेर्नियाव्स्की-पास्किन

9
सुधार: आधिकारिक तौर shlex.quote()पर 3.3 में प्रलेखित , pipes.quote()संगतता के लिए बनाए रखा गया। [ Bugs.python.org/issue9723]
बेनी चेर्नियाव्स्की-पास्किन

7
पाइप विंडोज पर काम नहीं करता है - दोहरे उद्धरणों के इंस्टेंट एकल उद्धरण जोड़ता है।
नक्स

58

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

निम्नलिखित PEP324 से है :

Replacing shell pipe line
-------------------------

output=`dmesg | grep hda`
==>
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

6
subprocess(विशेष रूप से check_callआदि के साथ ) अक्सर नाटकीय रूप से बेहतर होता है, लेकिन कुछ मामले हैं जहां शेल बचना अभी भी उपयोगी है। जब मैं भाग रहा होता हूं, तो मुख्य ssh दूरस्थ कमांड को लागू करने के लिए होता है।
क्रेग रिंगर

@ क्रेगिंगर, यूप, एसश रीमोटिंग जो मुझे यहां लाया है। : पीआई काश एसएचएस के पास यहां मदद के लिए कुछ था।
जुरगेन ए। इरहार्ड

@ JürgenA.Erhard यह अजीब लगता है कि इसमें एक --execvp- रिमोट विकल्प नहीं है (या डिफ़ॉल्ट रूप से इस तरह काम करते हैं)। शेल के माध्यम से सब कुछ करना अनाड़ी और जोखिम भरा लगता है। OTOH, ssh अजीब विचित्रताओं से भरा है, अक्सर "सुरक्षा" के संकीर्ण दृष्टिकोण में की गई चीजें होती हैं, जो लोगों को अधिक से अधिक असुरक्षित वर्कअराउंड के साथ आने का कारण बनाती हैं।
क्रेग रिंगर

10

शायद subprocess.list2cmdlineएक बेहतर शॉट है?


यह बहुत अच्छा लग रहा है। दिलचस्प है कि यह प्रलेखित नहीं है ... ( docs.python.org/library/subprocess.html पर कम से कम)
टॉम

4
यह ठीक से बच नहीं करता है \: subprocess.list2cmdline(["'",'',"\\",'"'])देता है' "" \ \"
टीनो

यह खोल विस्तार प्रतीकों से बच नहीं है
grep

क्या Subprocess.list2cmdline () केवल विंडोज के लिए है?
जेएस।

@JS हां, list2cmdlineविंडोज cmd.exe सिंटैक्स के अनुरूप है ( पायथन सोर्स कोड में फ़ंक्शन डॉकस्ट्रिंग देखें )। shlex.quoteयूनिक्स बॉर्न शेल सिंटैक्स के अनुरूप है, हालांकि यह आमतौर पर आवश्यक नहीं है क्योंकि यूनिक्स के पास सीधे तर्क देने के लिए अच्छा समर्थन है। विंडोज के लिए बहुत जरूरी है कि आप अपने सभी तर्कों के साथ एक स्ट्रिंग पास करें (इस प्रकार उचित भागने की आवश्यकता है)।
ईस्त्राद

7

ध्यान दें कि पाईप.क्वॉट वास्तव में पायथन 2.5 और पायथन 3.1 में टूटा हुआ है और उपयोग करने के लिए सुरक्षित नहीं है - यह शून्य-लम्बे तर्कों को संभालता नहीं है।

>>> from pipes import quote
>>> args = ['arg1', '', 'arg3']
>>> print 'mycommand %s' % (' '.join(quote(arg) for arg in args))
mycommand arg1  arg3

पायथन मुद्दे को देखें 7476 ; यह पायथन 2.6 और 3.2 और नए में तय किया गया है।


4
आप पायथन के किस संस्करण का उपयोग कर रहे हैं? संस्करण 2.6 सही उत्पादन का उत्पादन करने के लिए लगता है: mycommand arg1 '' arg3 (वे दो एकल-उद्धरण एक साथ हैं, हालांकि स्टैक ओवरफ्लो पर फ़ॉन्ट यह बताने के लिए कठिन बना देता है!)
ब्रैंडन रोड्स

4

सूचना : यह पायथन 2.7.x के लिए एक उत्तर है।

स्रोत के अनुसार , pipes.quote()" विश्वसनीय रूप से एक स्ट्रिंग को / बिन / श के लिए एकल तर्क के रूप में उद्धृत करना" का एक तरीका है । (हालांकि यह संस्करण 2.7 के बाद से हटा दिया गया है और अंत में पायथन 3.3 में सार्वजनिक रूप से shlex.quote()कार्य के रूप में उजागर हुआ है।)

पर दूसरी ओर , subprocess.list2cmdline()एक तरह से "करने के लिए है एक कमांड लाइन स्ट्रिंग में बहस का एक अनुक्रम अनुवाद, के रूप में ही नियमों का उपयोग एमएस सी क्रम "।

यहां हम कमांड लाइन के लिए स्ट्रिंग्स को उद्धृत करने का स्वतंत्र तरीका है।

import sys
mswindows = (sys.platform == "win32")

if mswindows:
    from subprocess import list2cmdline
    quote_args = list2cmdline
else:
    # POSIX
    from pipes import quote

    def quote_args(seq):
        return ' '.join(quote(arg) for arg in seq)

उपयोग:

# Quote a single argument
print quote_args(['my argument'])

# Quote multiple arguments
my_args = ['This', 'is', 'my arguments']
print quote_args(my_args)

3

मेरा मानना ​​है कि os.system केवल उपयोगकर्ता के लिए जो भी कमांड शेल कॉन्फ़िगर किया गया है, उसे इनवॉइस करता है, इसलिए मुझे नहीं लगता कि आप इसे एक स्वतंत्र तरीके से कर सकते हैं। मेरा कमांड शेल बैश, ईमैक्स, रूबी या क्वेक 3 से कुछ भी हो सकता है। इनमें से कुछ कार्यक्रम इस तरह की दलीलों की उम्मीद नहीं कर रहे हैं कि आप उनके पास से गुजर रहे हैं और भले ही उन्होंने ऐसा न किया हो, वे इस तरह से भागने की गारंटी देते हैं।


2
यह ज्यादातर या पूरी तरह से POSIX- आज्ञाकारी खोल (कम से कम हर जगह लेकिन विंडोज के साथ, और आपको पता है कि आपके पास "शेल" क्या है, वैसे भी) की उम्मीद करना अनुचित नहीं है। os.system $ SHELL का उपयोग नहीं करता है, कम से कम यहाँ नहीं।

2

मेरे द्वारा उपयोग किया जाने वाला कार्य है:

def quote_argument(argument):
    return '"%s"' % (
        argument
        .replace('\\', '\\\\')
        .replace('"', '\\"')
        .replace('$', '\\$')
        .replace('`', '\\`')
    )

वह यह है: मैं हमेशा दोहरे उद्धरणों में तर्क को संलग्न करता हूं, और फिर केवल दोहरे उद्धरणों के अंदर विशेष वर्णों का उद्धरण करता हूं।


ध्यान दें कि आपको '\\' ',' \\ $ 'और' \
_

1
इसके अतिरिक्त, कुछ (अजीब) स्थानों में दोहरे उद्धरण चिह्नों का उपयोग करने के मुद्दे हैं ; सुझाए गए pipes.quoteफ़िक्सेस का उपयोग करता है, जो @JohnWiseman ने बताया है कि वह भी टूट गया है। ग्रेग हेविल का जवाब इस प्रकार उपयोग करना है। (यह नियमित मामलों के लिए आंतरिक रूप से उपयोग किए जाने वाले गोले भी हैं।)
मिराबिलोस

-3

यदि आप सिस्टम कमांड का उपयोग करते हैं, तो मैं कोशिश करूंगा और श्वेतसूची में जो ओएस (सिस्टम) कॉल में जाता है .. उदाहरण के लिए ..

clean_user_input re.sub("[^a-zA-Z]", "", user_input)
os.system("ls %s" % (clean_user_input))

उपप्रोसेस मॉड्यूल एक बेहतर विकल्प है, और मैं जहाँ कहीं भी संभव हो वहाँ os.system / subprocess जैसी किसी भी चीज़ के उपयोग से बचने की कोशिश करूँगा।


-3

वास्तविक उत्तर है: os.system()पहली जगह में उपयोग न करें । subprocess.callइसके बजाय का उपयोग करें और unescaped तर्कों की आपूर्ति।


6
प्रश्न में एक उदाहरण है जहां उपप्रकार बस विफल हो जाता है। यदि आप उपप्रकार का उपयोग कर सकते हैं, तो आपको सुनिश्चित करना चाहिए। लेकिन अगर आप नहीं कर सकते ... सबप्रोसेस सब कुछ का हल नहीं है । ओह, और आपका जवाब सवाल का जवाब बिल्कुल नहीं है।
जुरगेन ए। इरहार्ड

@ JürgenA.Erd के ओपी उदाहरण विफल नहीं होते क्योंकि वह शेल पाइप का उपयोग करना चाहता है? आपको हमेशा उपप्रकार का उपयोग करना चाहिए क्योंकि यह एक शेल का उपयोग नहीं करता है। यह एक उदाहरण का थोड़ा अनाड़ी है , लेकिन आप देशी उपप्रकारों में पाइप कर सकते हैं, कुछ पीपीपी पैकेज हैं जो इसे आसान बनाने की कोशिश करते हैं। मैं सिर्फ इतना है कि मैं संभव के बाद अजगर में जरूरत के बाद प्रसंस्करण करते हैं, आप हमेशा अपने खुद के स्ट्रिंगर बफ़र्स बना सकते हैं और चीजों को पूरी तरह से उपप्रकारों के साथ नियंत्रित कर सकते हैं।
थोरसुमोनर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.