子进程更改目录

时间:2014-01-28 13:28:31

标签: python subprocess

我想在子目录/超级目录中执行一个脚本(我需要先在这个子/超级目录中)。我无法让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,我不知道为什么。无论我是尝试进入现有的子目录还是上一个目录(如上所述),我总是会遇到同样的错误。

8 个答案:

答案 0 :(得分:88)

您的代码尝试执行的操作是调用名为cd ..的程序。你想要的是调用名为cd的命令。

但是cd是一个shell内部。所以你只能把它称为

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

但这样做毫无意义。由于没有进程可以更改另一个进程的工作目录(同样,至少在类UNIX操作系统上,但在Windows上也是如此),此调用将具有子shell改变它的目录并立即退出。

使用os.chdir()subprocess命名参数cwd可以在执行子流程之前立即更改工作目录,从而实现所需。

例如,要在根目录中执行ls,您可以执行

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

或只是

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

答案 1 :(得分:36)

要将your_command作为其他目录中的子流程运行,请将cwd参数传递为suggested in @wim's answer

import subprocess

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

子进程无法更改其父级的工作目录(normally)。使用子流程在子shell进程中运行cd ..不会更改您的父Python脚本的工作目录,即the code example in @glglgl's answer is wrongcd是内置的shell(不是单独的可执行文件),它只能在相同的进程中更改目录。

答案 2 :(得分:24)

您希望使用可执行文件的绝对路径,并使用cwd Popen kwarg来设置工作目录。请参阅docs

  

如果cwd不是None,则子项的当前目录将更改为   cwd在执行之前。请注意,不考虑此目录   在搜索可执行文件时,您无法指定程序的路径   相对于cwd。

答案 3 :(得分: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'))

答案 4 :(得分:0)

我想这几天你会做:

import subprocess

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

答案 5 :(得分: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

答案 6 :(得分:0)

只需使用os.chdir
示例:

>>> import os
>>> import subprocess
>>> # Lets Just Say WE want To List The User Folders
>>> os.chdir("/home/")
>>> subprocess.run("ls")
user1 user2 user3 user4

答案 7 :(得分:-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