Alt işlem değiştirme dizini


99

Bir alt dizin / süper dizin içinde bir komut dosyası yürütmek istiyorum (önce bu alt / süper dizinin içinde olmam gerekiyor). Ben alamıyorum subprocessbenim alt dizini girmek için:

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

Python OSError'ı atıyor ve nedenini bilmiyorum. Var olan bir alt dizine mi yoksa bir dizine mi (yukarıdaki gibi) gitmeye çalıştığım önemli değil - her zaman aynı hatayla karşılaşıyorum.


1
Bunun os.chdir()yerine kullanılırsa ne olur ?
2014

Yanıtlar:


153

Kodunuzun yapmaya çalıştığı şey, adlı bir programı çağırmaktır cd ... İstediğin şey isimli bir komut çağırmak cd.

Ama cdbir iç kabuktur. Yani onu sadece şu şekilde arayabilirsin

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

Ama bunu yapmak anlamsız. Hiçbir işlem başka bir işlemin çalışma dizinini değiştiremeyeceğinden (yine, en azından UNIX benzeri bir işletim sisteminde ve Windows'ta), bu çağrı alt kabuğun dizinini değiştirmesini ve hemen çıkmasını sağlar.

İstediğiniz şey, bir alt işlemi yürütmeden hemen önce çalışma dizinini değiştiren adlandırılmış parametre ile os.chdir()veya bu subprocessparametre ile elde edilebilir cwd.

Örneğin ls, kök dizinde çalıştırmak için aşağıdakilerden birini yapabilirsiniz:

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

ya da sadece

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

1
cdgenellikle yalnızca yerleşik bir kabuk değil, ikili olarak da bulunur. OP'nin asıl sorunu cd .., evet, ikili çağırmasıydı . (Ve üçüncü paragrafınız bir sonraki problemi olurdu, çok iyi cevap.)
Leon Weber

@LeonWeber Nasıl cdikili olarak çalışmalı? Ebeveyninin çalışma dizinini zikredemez.
glglgl

2
Linux hakkında konuşuyordum. Yine de iyi bir nokta. Kendimi merak ediyordum ve işte cevap: /usr/bin/cdşunlardan oluşuyor builtin cd "$@"- bu yüzden sadece yerleşik kabuğu çağırıyor cd.
Leon Weber

1
@The_Diver Bu yüzden cddahili kabuk komutu olarak uygulanmalıdır. Bunu yapmanın başka yolu yok. İç kabuk komutları, kabuk ile aynı süreç içinde yürütülür. Alt kabuktan kastettiğim, bunun için çalıştırılan kabuktur shell=True. Yürütülecek komutu alır, yürütür ve çıkar.
glglgl

1
Önerdiğiniz yaklaşımlardan bir veya iki örnek faydalı olacaktır.
sscirrus

58

your_commandFarklı bir dizinde alt işlem olarak çalıştırmak için , @ wim'in yanıtında önerildiğicwd gibi parametreyi iletin :

import subprocess

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

Bir alt süreç, üst işleminin çalışma dizinini ( normalde ) değiştiremez. Koşu cd ..Python komut dosyasının çalışma dizini yani ebeveyninize değişmeyecek alt işlemi kullanarak bir çocuk kabuk sürecinde @ glglgl yanıtında kod örneği yanlıştır . cdbir kabuk yerleşiktir (ayrı bir çalıştırılabilir değil), dizini yalnızca aynı işlemde değiştirebilir.


24

Çalıştırılabilir dosyanın mutlak yolunu kullanmak ve çalışma dizinini ayarlamak için cwdkwarg'ı kullanmak istiyorsunuz Popen. Dokümanlara bakın .

Cwd None değilse, alt dizini çalıştırılmadan önce cwd olarak değiştirilecektir. Çalıştırılabilir dosya aranırken bu dizinin dikkate alınmadığını unutmayın, bu nedenle programın cwd'ye göre yolunu belirtemezsiniz.


Başka bir alt işlemin yürütülüp yürütülmemesine bağlıdır. Eğer öyleyse, yolunuz doğru olanıdır. Ancak, yalnızca farklı bir dizinde hareket eden kendi programına sahip olmak yardımcı olmaz.
glglgl

Yardımı olmayacağı ne demek? Bunu yapmanın tek açık yolu budur.
wim

1
Hayır, sadece başlatacağım sürecin cwd'sini değiştirdiği için, örneğin subprocess.call(['ls', '-l'], cwd='/'). Bu kadar cwd değiştirir /ve sonra ishal lsile -largüman olarak. Ama yapmak istersem os.chdir('/')ve sonra open('etc/fstab', 'r'), söylendiği gibi yardımcı olmayacağı için os.chdir()hiçbir şeyle değiştiremem subprocess.XXX(cwd='/'). Bunlar tamamen farklı iki senaryodur.
glglgl

Bu yüzden cevabım yürütülebilir dosyaya mutlak bir yol kullanmak diyor, o kısmı kaçırdınız mı?
wim

2
Hayır, yapmadım. Sanırım pes ediyorum. Mevcut çalışma dizinini değiştirmek ve bir dosya açmak istersem, yürütülebilir dosyam yok. Tamamen farklı bir durum. BTW: Amaçlandığı gibi kullanırsam mutlak bir yol kullanmaya gerek yoktur cwd=. Ben de yapabilirim subprocess.call(['bin/ls', '-l'], cwd='/').
glglgl

18

subprocess.callve subprocessmodüldeki diğer yöntemlerin bir cwdparametresi vardır.

Bu parametre, işleminizi yürütmek istediğiniz çalışma dizinini belirler.

Böylece bunun gibi bir şey yapabilirsiniz:

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

Docs subprocess.popen-constructor'a göz atın


7

Bu yanıta dayalı başka bir seçenek: https://stackoverflow.com/a/29269316/451710

Bu cd, aynı işlemde birden fazla komutu (örneğin ) çalıştırmanıza olanak tanır .

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
Bu sadece dolambaçlı ve verimsiz bir yolshell=True, executable='/bin/bash'
üç kat

3

Sanırım bu günlerde yapardın:

import subprocess

subprocess.run(["pwd"], cwd="sub-dir")

0

Eğer cd işlevselliğine sahip olmak istiyorsanız (kabuk = True varsayarak) ve yine de dizini Python betiği açısından değiştirmek istiyorsanız, bu kod 'cd' komutlarının çalışmasına izin verecektir.

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

Dizini değiştirmeniz gerekirse, bir komut çalıştırın ve std çıktısını da alın:

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_callKötü bir şekilde yeniden keşfediyorsun .
üçlü
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.