python - Subprocess.Popen से "स्रोत" कमांड को कॉल करना




unix (5)

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

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

import subprocess
pipe = subprocess.Popen(". ./shellscript.sh; python -c 'import os; print \"newenv = %r\" % os.environ'", 
    stdout=subprocess.PIPE, shell=True)
exec(pipe.communicate()[0])
os.environ.update(newenv)

शायद एक साफ रास्ता है? इससे यह भी सुनिश्चित होता है कि अगर कोई व्यक्ति स्क्रिप्ट में एक इको स्टेटमेंट डालता है तो पर्यावरण पार्सिंग गड़बड़ नहीं होती है। बेशक, यहां एक निष्पादन है इसलिए गैर-भरोसेमंद इनपुट के बारे में सावधान रहें ... लेकिन मुझे लगता है कि एक मनमाने ढंग से खोल स्क्रिप्ट को स्रोत / निष्पादित करने के बारे में चर्चा में अंतर्निहित है ;-)

अद्यतन: env आउटपुट में न्यूलाइन को संभालने के लिए वैकल्पिक (संभवतः अच्छे) तरीके के लिए @xApple उत्तर पर @ unutbu की टिप्पणी देखें।

मेरे पास एक .sh स्क्रिप्ट है जिसे मैं source the_script.sh साथ कॉल करता source the_script.sh । इसे नियमित रूप से कॉल करना ठीक है। हालांकि, मैं इसे अपनी पाइथन लिपि से subprocess.Popen माध्यम से कॉल करने की कोशिश कर रहा हूं। subprocess.Popen

इसे पॉपन से कॉल करना, मुझे निम्नलिखित दो परिदृश्य कॉल में निम्न त्रुटियां मिल रही हैं:

foo = subprocess.Popen("source the_script.sh")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 672, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1213, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory


>>> foo = subprocess.Popen("source the_script.sh", shell = True)
>>> /bin/sh: source: not found

क्या देता है? मैं पाइपन से बाहर "स्रोत" क्यों नहीं कह सकता, जब मैं अजगर के बाहर कर सकता हूं?


आप केवल एक सबहेल में कमांड चला सकते हैं और वर्तमान वातावरण को अद्यतन करने के लिए परिणामों का उपयोग कर सकते हैं।

def shell_source(script):
    """Sometime you want to emulate the action of "source" in bash,
    settings some environment variables. Here is a way to do it."""
    import subprocess, os
    pipe = subprocess.Popen(". %s; env" % script, stdout=subprocess.PIPE, shell=True)
    output = pipe.communicate()[0]
    env = dict((line.split("=", 1) for line in output.splitlines()))
    os.environ.update(env)

टूटा हुआ Popen("source the_script.sh") Popen(["source the_script.sh"]) बराबर है जो 'source the_script.sh' प्रोग्राम लॉन्च करने में असफल प्रयास करता है। इसे नहीं मिला, इसलिए "No such file or directory" त्रुटि।

टूटा हुआ Popen("source the_script.sh", shell=True) विफल रहता है क्योंकि source एक बैश बिल्टिन कमांड है (बैश में help source टाइप करें) लेकिन डिफ़ॉल्ट खोल /bin/sh जो इसे समझ में नहीं आता है ( /bin/sh उपयोग करता है . )। मान लीजिए कि the_script.sh में अन्य bash-ism हो सकता है, इसे बैश का उपयोग करके चलाया जाना चाहिए:

foo = Popen("source the_script.sh", shell=True, executable="/bin/bash")

जैसा कि @IfLoop ने कहा , उपप्रोसेसर में source निष्पादित करना बहुत उपयोगी नहीं है क्योंकि यह माता-पिता के पर्यावरण को प्रभावित नहीं कर सकता है।

os.environ.update(env) -आधारित विधियां विफल होती हैं the_script.sh कुछ चर के लिए unset the_script.sh निष्पादित करता है। os.environ.clear() को पर्यावरण को रीसेट करने के लिए बुलाया जा सकता है:

#!/usr/bin/env python
import os
from pprint import pprint
from subprocess import check_output

os.environ['a'] = 'a'*100
# POSIX: name shall not contain '=', value doesn't contain '\0'
output = check_output("source the_script.sh; env -0",   shell=True,
                      executable="/bin/bash")
# replace env
os.environ.clear() 
os.environ.update(line.partition('=')[::2] for line in output.split('\0'))
pprint(dict(os.environ)) #NOTE: only `export`ed envvars here

यह @unutbu द्वारा सुझाए गए env -0 और .split('\0') का उपयोग करता है

os.environb में मनमाने ढंग से बाइट्स का समर्थन करने के लिए, os.environb मॉड्यूल का उपयोग किया जा सकता है (मान लीजिए कि हम पाइथन संस्करण का उपयोग करते हैं, जहां "json.dumps json.loads द्वारा पारदर्शी नहीं है" समस्या तय है):

पाइप के माध्यम से पर्यावरण को पार करने से बचने के लिए, पाइथन कोड को सबप्रोसेस पर्यावरण में खुद को बुलावा देने के लिए बदला जा सकता है उदाहरण:

#!/usr/bin/env python
import os
import sys
from pipes import quote
from pprint import pprint

if "--child" in sys.argv: # executed in the child environment
    pprint(dict(os.environ))
else:
    python, script = quote(sys.executable), quote(sys.argv[0])
    os.execl("/bin/bash", "/bin/bash", "-c",
        "source the_script.sh; %s %s --child" % (python, script))

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

यह काम नहीं करेगा यदि आपको पायथन संदर्भ को संशोधित करने की आवश्यकता है, जहां आपका प्रोग्राम चल रहा है।


source निष्पादन योग्य कमांड नहीं है, यह एक खोल बनाया गया है।

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

सब-प्रोसेस बनाना और सबप्रोसेस में source का उपयोग करना संभवतः कुछ भी उपयोगी नहीं होगा, यह मूल प्रक्रिया के वातावरण को संशोधित नहीं करेगा, सोर्स की गई स्क्रिप्ट का उपयोग करने के दुष्प्रभावों में से कोई भी नहीं होगा।

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





popen