ディレクトリを変更するサブプロセス


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

PythonはOSErrorをスローしますが、その理由はわかりません。(上記のように)既存のサブディレクトリに移動しようとしても、1つのディレクトリに移動しようとしても、常に同じエラーが発生します。


1
os.chdir()代わりに使用するとどうなりますか。
greole 2014年

回答:


151

コードが実行しようとしているのは、という名前のプログラムを呼び出すことですcd ..。必要なのは、という名前のコマンドを呼び出すことですcd

しかしcd、内部のシェルです。だからあなたはそれを次のように呼ぶことができるだけです

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

しかし、そうすることは無意味です。どのプロセスも別のプロセスの作業ディレクトリを変更できないため(少なくともUNIXライクなOSでも、Windowsでも)、この呼び出しではサブシェルのディレクトリが変更され、すぐに終了します。

サブプロセスを実行する直前に作業ディレクトリを変更する名前付きパラメータを使用os.chdir()して、または使用して、目的を達成できます。subprocesscwd

たとえばls、ルートディレクトリで実行するには、次のいずれかを実行できます。

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

または単に

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

1
cd通常、組み込みのシェルだけでなく、バ​​イナリとしても存在します。OPの本当の問題は、彼がバイナリを呼び出していたということでしたcd ..。(そしてあなたの3番目の段落は彼の次の問題だったでしょう、それで良い答えです。)
Leon Weber

@LeonWebercdバイナリとして機能するにはどうすればよいですか?親の作業ディレクトリをチャントすることはできません。
glglgl 2014年

2
私はLinuxについて話していました。でも良い点です。私は自分自身を不思議に思っていました、そしてここに答えがあります:で/usr/bin/cd構成されていますbuiltin cd "$@"—それは単に組み込みのシェルも呼び出すcdだけです。
レオンウェーバー

1
@The_Diverそのcdため、内部シェルコマンドとして実装する必要があります。それを行う他の方法はありません。内部シェルコマンドは、シェルと同じプロセス内で実行されます。サブシェルが意味するのは、に対して実行されるシェルですshell=True。実行するコマンドを取得して実行し、終了します。
glglgl 2015年

1
提案されたアプローチの例または2つが役立つと思います。
sscirrus 2017

57

your_command別のディレクトリでサブプロセスとして実行するには、@ wimの回答で提案されcwdているように、パラメータを渡します。

import subprocess

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

子プロセスは、その親の作業ディレクトリを変更できません(通常)。cd ..サブプロセスを使用して子シェルプロセスで実行しても、親Pythonスクリプトの作業ディレクトリは変更されません。つまり、@ glglglの回答のコード例は間違っています。cdはシェル組み込み(個別の実行可能ファイルではありません)であり、同じプロセスでのみディレクトリを変更できます。


24

実行可能ファイルへの絶対パスを使用し、のcwdkwargを使用しPopenて作業ディレクトリを設定します。ドキュメントを参照してください。

cwdがNoneでない場合、子の現在のディレクトリは実行される前にcwdに変更されます。実行可能ファイルを検索するときにこのディレクトリは考慮されないため、cwdを基準にしたプログラムのパスを指定できないことに注意してください。


別のサブプロセスが実行されることになっているのかどうかによって異なります。もしそうなら、あなたの方法は正しいものです。しかし、独自のプログラムを別のディレクトリ内で動作させるだけでは、それは役に立ちません。
glglgl 2014年

それが役に立たないというのはどういう意味ですか?これは、それを行うための1つの明白な方法です。
2014年

1
いいえ、起動するプロセスのcwdを変更するだけなので、subprocess.call(['ls', '-l'], cwd='/')。これにより、cwdがに変更され、引数として/実行ls-lれます。しかし、私がやりたいと思ったらos.chdir('/')、それは役に立たopen('etc/fstab', 'r')ないので、私はos.chdir()何にも置き換えることはできませんsubprocess.XXX(cwd='/')。これらは2つの完全に異なるシナリオです。
glglgl 2014年

だから私の答えは実行可能ファイルへの絶対パスを使用するように言っています、あなたはその部分を逃しましたか?
2014年

2
いいえ、しませんでした。あきらめたと思います。現在の作業ディレクトリを変更してファイルを開きたい場合、実行可能ファイルがありません。全く違う状況です。ところで:cwd=意図したとおりに使用する場合は、絶対パスを使用する必要はありません。私もできますsubprocess.call(['bin/ls', '-l'], cwd='/')
glglgl 2014年

18

subprocess.callsubprocessモジュール内の他のメソッドにはcwdパラメーターがあります。

このパラメータは、プロセスを実行する作業ディレクトリを決定します。

したがって、次のようなことができます。

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

docssubprocess.popen-constructorをチェックしてください


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'
トリプリー2018

3

私は最近あなたがするだろうと思います:

import subprocess

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

0

cd機能が必要で(shell = Trueと仮定)、Pythonスクリプトの観点からディレクトリを変更したい場合は、このコードで「cd」コマンドを機能させることができます。

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

ディレクトリを変更する必要がある場合は、コマンドを実行して、std出力も取得します。

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貧弱に再発明しています。
トリプリー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.