सबप्रोसेस बदलती निर्देशिका


98

मैं एक उपनिर्देशिका / सुपरनिर्देशिका के अंदर एक स्क्रिप्ट निष्पादित करना चाहता हूं (मुझे पहले इस उप / सुपर-डायरेक्टरी के अंदर होना चाहिए)। मुझे subprocessअपनी उपनिर्देशिका दर्ज करने की अनुमति नहीं मिल सकती है :

tducin@localhost:~/Projekty/tests/ve$ python
Python 2.7.4 (default, Sep 26 2013, 03:20:26) 
[GCC 4.7.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> import os
>>> os.getcwd()
'/home/tducin/Projekty/tests/ve'
>>> subprocess.call(['cd ..'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 524, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1308, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

अजगर OSError फेंकता है और मुझे पता नहीं क्यों। इससे कोई फर्क नहीं पड़ता कि क्या मैं किसी मौजूदा उपखंड में जाने की कोशिश करता हूं या एक निर्देशिका ऊपर (जैसा कि ऊपर) जाता हूं - मैं हमेशा एक ही त्रुटि के साथ समाप्त होता हूं।


1
os.chdir()इसके बजाय यदि उपयोग किया जाए तो क्या होगा ।
ग्रेले

जवाबों:


151

आपका कोड क्या करने की कोशिश करता है, नाम का एक कार्यक्रम है cd ..। आप जो चाहते हैं उसे एक कमांड का नाम दिया जाता है cd

लेकिन cdएक खोल आंतरिक है। इसलिए आप इसे केवल कह सकते हैं

subprocess.call('cd ..', shell=True) # pointless code! See text below.

लेकिन ऐसा करना व्यर्थ है। जैसा कि कोई भी प्रक्रिया किसी अन्य प्रक्रिया की कार्यशील निर्देशिका को नहीं बदल सकती (फिर से, कम से कम UNIX-like OS पर, लेकिन साथ ही विंडोज पर), इस कॉल की सब-डिले अपने परिवर्तन और तुरंत बाहर निकल जाएगी।

आप जो चाहते हैं उसे नामांकित पैरामीटर के साथ os.chdir()या उसके साथ प्राप्त किया जा सकता है जो उपप्रकार को निष्पादित करने से तुरंत पहले कार्य निर्देशिका को बदल देता है।subprocesscwd

उदाहरण के लिए, lsरूट निर्देशिका में निष्पादित करने के लिए , आप या तो कर सकते हैं

wd = os.getcwd()
os.chdir("/")
subprocess.Popen("ls")
os.chdir(wd)

या केवल

subprocess.Popen("ls", cwd="/")

1
cdआम तौर पर एक बाइनरी के रूप में भी मौजूद होता है, न केवल एक शेल अंतर्निर्मित। ओपी की असली समस्या यह थी कि वह एक बाइनरी बुला रहा था cd .., हाँ। (और आपका तीसरा पैराग्राफ उसकी अगली समस्या होगी, इतना अच्छा जवाब।)
लियोन वेबर

@LeonWeber cdबाइनरी के रूप में कैसे काम करने में सक्षम होना चाहिए ? यह अपने माता-पिता के कामकाज के लिए जप नहीं कर सकता।
glglgl

2
मैं लिनक्स के बारे में बात कर रहा था। हालांकि अच्छी बात है। मैं अपने आप को आश्चर्यचकित कर रहा था, और यहाँ का जवाब है: /usr/bin/cdइसमें शामिल हैं builtin cd "$@"- इसलिए यह केवल शेल में निर्मित कॉल को कहते हैं cd
लियोन वेबर

1
@The_Diver इसीलिए cdआंतरिक शेल कमांड के रूप में लागू किया जाना चाहिए। इसे करने का कोई और तरीका नहीं है। आंतरिक शेल कमांड को शेल के समान प्रक्रिया के भीतर निष्पादित किया जाता है। मुझे जो सबस्क्रिप्शन से मतलब था, उसके लिए निष्पादित शेल है shell=True। इसे निष्पादित होने, निष्पादित करने और बाहर निकलने की आज्ञा मिलती है।
ग्लोगल

1
मुझे लगता है कि एक उदाहरण या आपके सुझाए दृष्टिकोण में से दो उपयोगी होंगे।
sscirrus

57

your_commandएक अलग निर्देशिका में एक उपप्रकार के रूप में चलाने के लिए , cwdपैरामीटर को @ wim के उत्तर में सुझाया गया है :

import subprocess

subprocess.check_call(['your_command', 'arg 1', 'arg 2'], cwd=working_dir)

एक बच्चा प्रक्रिया अपने माता-पिता की कामकाजी निर्देशिका ( सामान्य रूप से ) को बदल नहीं सकती है । सबप्रोसेस काcd .. उपयोग करके एक चाइल्ड शेल प्रक्रिया में चलना आपके माता-पिता की स्क्रिप्ट की कार्यशील निर्देशिका को नहीं बदलेगा, अर्थात @ glglgl के उत्तर में कोड उदाहरण गलत हैcdएक शेल बिल्टिन (एक अलग निष्पादन योग्य नहीं) है, यह केवल उसी प्रक्रिया में निर्देशिका को बदल सकता है।


24

आप निष्पादन योग्य के लिए एक निरपेक्ष पथ का उपयोग करना चाहते हैं, और काम करने वाले निर्देशिका को निर्धारित करने cwdके Popenलिए kwarg का उपयोग करते हैं । डॉक्स देखें ।

यदि cwd कोई नहीं है, तो निष्पादित होने से पहले बच्चे की वर्तमान निर्देशिका को cwd में बदल दिया जाएगा। ध्यान दें कि निष्पादन योग्य खोजते समय इस निर्देशिका पर विचार नहीं किया जाता है, इसलिए आप प्रोग्राम के मार्ग को cwd के सापेक्ष निर्दिष्ट नहीं कर सकते।


यह निर्भर करता है कि क्या किसी अन्य उपप्रकार को निष्पादित किया जाना है। यदि हां, तो आपका तरीका सही है। लेकिन केवल एक अलग निर्देशिका के अंदर अभिनय करने वाले खुद के कार्यक्रम के लिए, यह मदद नहीं करेगा।
ग्लोगल

तुम्हारा क्या मतलब है यह मदद नहीं करेगा? यह ऐसा करने का एक स्पष्ट तरीका है।
विम

1
नहीं, क्योंकि यह सिर्फ उस प्रक्रिया का cwd बदलता है जिसे मैं लॉन्च करने जा रहा हूं, जैसे कि subprocess.call(['ls', '-l'], cwd='/')। यह करने के लिए CWD बदल जाता है /और उसके बाद चलाता है lsके साथ -lतर्क के रूप में। लेकिन अगर मैं करना चाहता हूं os.chdir('/')और फिर open('etc/fstab', 'r'), मैं os.chdir()इसके बारे में कुछ भी नहीं बदल सकताsubprocess.XXX(cwd='/') क्योंकि यह मदद नहीं करेगा, जैसा कि कहा गया है। ये दो पूर्ण भिन्न परिदृश्य हैं।
ग्लोगल

यही कारण है कि मेरा उत्तर निष्पादन योग्य के लिए एक निरपेक्ष पथ का उपयोग करने के लिए कहता है, क्या आप उस हिस्से को याद करते हैं?
विम

2
नहीं, मैंने नहीं किया। मुझे लगता है कि मैं हार मान लेता हूं। यदि मैं वर्तमान कार्यशील निर्देशिका को बदलना और फ़ाइल खोलना चाहता हूं , तो मेरे पास कोई निष्पादन योग्य नहीं है। यह पूरी तरह से अलग स्थिति है। BTW: अगर मैं cwd=इरादा के रूप में उपयोग करता है एक निरपेक्ष मार्ग का उपयोग करने की कोई जरूरत नहीं है । मैं भी कर सकता हूं subprocess.call(['bin/ls', '-l'], cwd='/')
ग्लोगल

17

subprocess.callऔर subprocessमॉड्यूल में अन्य विधियों में एक cwdपैरामीटर है।

यह पैरामीटर कार्यशील निर्देशिका को निर्धारित करता है जहां आप अपनी प्रक्रिया को निष्पादित करना चाहते हैं।

तो आप ऐसा कुछ कर सकते हैं:

subprocess.call('ls', shell=True, cwd='path/to/wanted/dir/')

डॉक्स सबप्रोसेस.पोपेन-कंस्ट्रक्टर देखें


7

इस उत्तर पर आधारित एक अन्य विकल्प: https://stackoverflow.com/a/29269316/451710

यह आपको cdएक ही प्रक्रिया में कई कमांड (जैसे ) निष्पादित करने की अनुमति देता है।

import subprocess

commands = '''
pwd
cd some-directory
pwd
cd another-directory
pwd
'''

process = subprocess.Popen('/bin/bash', stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out, err = process.communicate(commands.encode('utf-8'))
print(out.decode('utf-8'))

1
यह करने के लिए सिर्फ एक गोल और अकुशल तरीका हैshell=True, executable='/bin/bash'
ट्रिपल डी


0

यदि आप सीडी कार्यक्षमता (शेल = सच मानकर) चाहते हैं और अभी भी पायथन स्क्रिप्ट के संदर्भ में निर्देशिका को बदलना चाहते हैं, तो यह कोड 'सीडी' कमांड को काम करने की अनुमति देगा।

import subprocess
import os

def cd(cmd):
    #cmd is expected to be something like "cd [place]"
    cmd = cmd + " && pwd" # add the pwd command to run after, this will get our directory after running cd
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) # run our new command
    out = p.stdout.read()
    err = p.stderr.read()
    # read our output
    if out != "":
        print(out)
        os.chdir(out[0:len(out) - 1]) # if we did get a directory, go to there while ignoring the newline 
    if err != "":
        print(err) # if that directory doesn't exist, bash/sh/whatever env will complain for us, so we can just use that
    return

-1

यदि आपको निर्देशिका बदलने की आवश्यकता है, तो एक कमांड चलाएं और साथ ही एसटीडी आउटपुट प्राप्त करें:

import os
import logging as log
from subprocess import check_output, CalledProcessError, STDOUT
log.basicConfig(level=log.DEBUG)

def cmd_std_output(cd_dir_path, cmd):
    cmd_to_list = cmd.split(" ")
    try:
        if cd_dir_path:
            os.chdir(os.path.abspath(cd_dir_path))
        output = check_output(cmd_to_list, stderr=STDOUT).decode()
        return output
    except CalledProcessError as e:
        log.error('e: {}'.format(e))
def get_last_commit_cc_cluster():
    cd_dir_path = "/repos/cc_manager/cc_cluster"
    cmd = "git log --name-status HEAD^..HEAD --date=iso"
    result = cmd_std_output(cd_dir_path, cmd)
    return result

log.debug("Output: {}".format(get_last_commit_cc_cluster()))

Output: "commit 3b3daaaaaaaa2bb0fc4f1953af149fa3921e\nAuthor: user1<user1@email.com>\nDate:   2020-04-23 09:58:49 +0200\n\n

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