하위 프로세스 변경 디렉터리


104

하위 디렉터리 / 수퍼 디렉터리 내에서 스크립트를 실행하고 싶습니다 (먼저이 하위 / 수퍼 디렉터리에 있어야 함). 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()대신 사용하면 어떻게 되나요 ?
greole

답변:


155

코드에서하려는 것은라는 프로그램을 호출하는 것 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 ... (그리고 세 번째 단락은 좋은 답변, 그래서 그의 다음 문제를했을 것이다.)
레온 웨버

@LeonWeber cd바이너리로 작동 하려면 어떻게해야 합니까? 부모의 작업 디렉토리를 외울 수 없습니다.
glglgl

2
나는 리눅스에 대해 이야기하고 있었다. 그래도 좋은 지적입니다. 나는 나 자신을 궁금해하고 있었고, 여기에 답이 있습니다. /usr/bin/cd구성됨 builtin cd "$@"— 쉘 내장이라고 부르기 cd도합니다.
Leon Weber

1
@The_Diver 그래서 cd내부 쉘 명령으로 구현해야합니다. 다른 방법은 없습니다. 내부 쉘 명령은 쉘과 동일한 프로세스 내에서 실행됩니다. 내가 subshell이 ​​의미하는 것은 shell=True. 실행할 명령을 가져 와서 실행하고 종료합니다.
glglgl

1
제안 된 접근 방식 중 한두 가지가 유용 할 것이라고 생각합니다.
sscirrus

58

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
아니요, 시작할 프로세스의 cwd (예 : subprocess.call(['ls', '-l'], cwd='/'). 이에 CWD를 변경 /한 후 실행 ls-l인수로. 내가하고 싶다면 os.chdir('/')다음과 open('etc/fstab', 'r')나는 대체 할 수 os.chdir()에 대해 아무것도와 subprocess.XXX(cwd='/')그렇지 않은 도움뿐만 말했다 것 같은. 이것은 완전히 다른 두 가지 시나리오입니다.
glglgl

그래서 내 대답은 실행 파일에 대한 절대 경로를 사용하라고 말하는 이유입니다. 그 부분을 놓쳤습니까?
WIM

2
아뇨. 포기한 것 같아요. 현재 작업 디렉토리를 변경하고 파일을 열려면 실행 파일이 없습니다. 완전히 다른 상황입니다. BTW : cwd=의도 한대로 사용하면 절대 경로를 사용할 필요가 없습니다 . 나도 할 수 있습니다 subprocess.call(['bin/ls', '-l'], cwd='/').
glglgl

19

subprocess.callsubprocess모듈의 다른 메소드 에는 cwd매개 변수가 있습니다.

이 매개 변수는 프로세스를 실행할 작업 디렉토리를 결정합니다.

따라서 다음과 같이 할 수 있습니다.

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

문서 확인 subprocess.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'
tripleee

6

나는 요즘 당신이 할 것이라고 생각합니다.

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하고 있습니다.
tripleee
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.