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




unix (7)

टूटा हुआ 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))

मेरे पास एक .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

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


source एक बैश-विशिष्ट खोल अंतर्निहित है (और गैर-इंटरैक्टिव गोले अक्सर बैश के बजाय हल्के डैश शैल होते हैं)। इसके बजाए, बस कॉल करें /bin/sh :

foo = subprocess.Popen(["/bin/sh", "the_script.sh"])

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

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

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

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


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

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)

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

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


इस पर बहुत सारे जवाब प्रतीत होते हैं, उन सभी को नहीं पढ़ा है, इसलिए वे पहले से ही इसे इंगित कर सकते हैं; लेकिन, जब इस तरह के खोल कमांड को कॉल करते हैं, तो आपको पॉप = कॉल के लिए खोल = सही पास करना होगा। अन्यथा, आप Popen (shlex.split ()) को कॉल कर सकते हैं। श्लेक्स आयात करना सुनिश्चित करें।

मैं वास्तव में फ़ाइल को सोर्सिंग और वर्तमान वातावरण को संशोधित करने के उद्देश्य से इस फ़ंक्शन का उपयोग करता हूं।

def set_env(env_file):
    while True:
        source_file = '/tmp/regr.source.%d'%random.randint(0, (2**32)-1)
        if not os.path.isfile(source_file): break
    with open(source_file, 'w') as src_file:
        src_file.write('#!/bin/bash\n')
        src_file.write('source %s\n'%env_file)
        src_file.write('env\n')
    os.chmod(source_file, 0755)
    p = subprocess.Popen(source_file, shell=True,
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (out, err) = p.communicate()
    setting = re.compile('^(?P<setting>[^=]*)=')
    value = re.compile('=(?P<value>.*$)')
    env_dict = {}
    for line in out.splitlines():
        if setting.search(line) and value.search(line):
            env_dict[setting.search(line).group('setting')] = value.search(line).group('value')
    for k, v in env_dict.items():
        os.environ[k] = v
    for k, v in env_dict.items():
        try:
            assert(os.getenv(k) == v)
        except AssertionError:
            raise Exception('Unable to modify environment')

NylonSmile के जवाब के बावजूद, जो "तरह का" सही है .. मैं इस तरह से फ़ाइलों को ओवरराइट करने में असमर्थ था ..

echo "i know about Pipes, girlfriend" > thatAnswer

zsh: file exists: thatAnswer

मेरे मुद्दों को हल करने के लिए .. मुझे उपयोग करना था ... >! , ला ला ..

[[ $FORCE_IT == 'YES' ]] && echo "[email protected]" >! "$X" || echo "[email protected]" > "$X"

जाहिर है, इस से सावधान रहें ...





python unix popen