2016-08-03 9 views
0

저는 분명히 우분투 15.04 (Python 3.4.3)가 아니며 다음과 같은 것을 실행하려고합니다. 내가 실행하기 위해 노력하고있어 실제 코드를 해석 할 필요가 와일드 카드를 포함하고 있기 때문에 Python subprocess.check_call()은 pushd 및 popd를 인식하지 않습니다.

subprocess.check_call("pushd /tmp", shell=True) 

은 내가 shell=True이 필요합니다. 그러나이 다음과 같은 오류가 발생합니다.

/usr/lib/python3.4/subprocess.py in check_call(*popenargs, **kwargs) 
    559   if cmd is None: 
    560    cmd = popenargs[0] 
--> 561   raise CalledProcessError(retcode, cmd) 
    562  return 0 
    563 

CalledProcessError: Command 'pushd /tmp' returned non-zero exit status 127 

내 Mac (El Capitan 및 Python 3.5.1)에서 동일한 작업을 시도했지만 완벽하게 작동합니다. 나는 또한 우분투 15.04에서 Python 3.4.3 (온 전성 체크 용)을 사용하여 subprocess.check_call("ls", shell=True)을 실행 해 보았습니다. 정상적으로 작동합니다. 마지막으로 정상적인 확인으로 나는 우분투 15.04에서 Bash로 pushd /tmp && popd 명령을 시도했으나 제대로 작동합니다. 그래서 어쨌든, (내) 우분투 15.04와 파이썬 3.4.3에서 subprocess.check_call()pushdpopd을 인식하지 못합니다! 왜?

답변

3

코드에 두 가지 문제점이 있습니다. 첫 번째는 기본으로 사용되는 쉘이 /bin/sh이고 pushdpopd을 지원하지 않는다는 것입니다. 귀하의 질문에 당신은 전체 오류 출력을 제공하는 데 실패, 그리고 그것의 상단에 당신은 라인 표시되어야합니다

/bin/sh: 1: popd: not found 

은 다음 시간이 전체 오류 메시지를 게시 할 rememeber하고, 단지 부분을 그 (잘못) 생각하는 것이 관련이 있습니다.

당신은 쉘이 executable 인수를 통해 사용할 수있는 subprocess 모듈을 말함으로써이 문제를 해결할 수 있습니다

>>> subprocess.check_call('pushd ~', shell=True, executable='/bin/bash') 
~ ~ 
0 

두 번째 문제는 여러 check_call 전화를 사용하는 경우에도이 함께 오류가 발생하는 것입니다 :

P
>>> subprocess.check_call('pushd ~', shell=True, executable='/bin/bash') 
~ ~ 
0 
>>> subprocess.check_call('popd', shell=True, executable='/bin/bash') 
/bin/bash: riga 0: popd: stack delle directory vuoto 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/python3.5/subprocess.py", line 581, in check_call 
    raise CalledProcessError(retcode, cmd) 
subprocess.CalledProcessError: Command 'popd' returned non-zero exit status 1 

이것은 check_call에 대한 모든 호출은 새로운 서브 쉘을 시작하기 때문에, 따라서 당신의 여부는 중요하지 않습니다 디렉터리 스택이 항상 비어 있기 때문에 나중에 pushd이라고 불렀습니다. 당신이 파이썬에서 그런 식으로 pushdpopd를 사용하여 생각한다면,

>>> subprocess.check_call('pushd ~ && popd', shell=True, executable='/bin/bash') 
~ ~ 
~ 
0 

이제 사실은 : 당신은 하나의 호출에 pushdpopd을 결합하려고하면 그들이 일을 것을

참고. .. 그들은 쓸데없는입니다.

current_working_dirs = [] 

def pushd(dir): 
    current_working_dirs.append(os.path.realpath(os.path.expanduser(dir))) 

def popd(): 
    current_working_dirs.pop() 


def run_command(cmdline, **kwargs): 
    return subprocess.check_call(cmdline, cwd=current_working_dirs[-1], **kwargs) 

pushd('xxx')check_call('popd')check_call('pushd xxx') 교체 : 당신이 cwd 인수를 통해 현재 작업 디렉토리를 지정할 수 있습니다, 그래서 당신은 pushdpopd에 의존하지 않고 파이썬에서 작업 디렉토리의 스택을 추적 할 수 있기 때문이다 popd으로 바꾸고 check_call(...) 대신 run_command(...)을 사용하십시오.


좀 더 우아한 해결책이 컨텍스트 매니저 사용하는 것이 좋습니다로서 : 지금 내 질문을 편집 한

with Pwd('~') as shell: 
    shell.run(command) 
    with Pwd('/other/directory') as shell: 
     shell.run(command2) # runs in '/other/directory' 
    shell.run(command3)  # runs in '~' 
+0

:

class Pwd: dir_stack = [] def __init__(self, dirname): self.dirname = os.path.realpath(os.path.expanduser(self.dirname)) def __enter__(self): Pwd.dir_stack.append(self.dirname) return self def __exit__(self, type, value, traceback): Pwd.dir_stack.pop() def run(self, cmdline, **kwargs): return subprocess.check_call(cmdline, cwd=Pwd.dir_stack[-1], **kwargs) 

으로 사용합니다. 죄송합니다. 일찍 실수하셨습니다. 나는'check_call()'이 새로운 쉘을 생성한다는 것을 알고있다. 문제는'pushd'를 호출 한 후'popd'를 호출하는 것이 아닙니다. 그것은 정말로'pushd' 자체와 함께합니다. – Ray

+1

@ 레이 귀하의 업데이 트를 기반으로, Bakuriu의 대답의 핵심 부분은 쉘이 배쉬가 아니므로 사용할 수있는 푸시가 없다는 것입니다. 우분투에서 sh를 시작하고 밀어 붙이십시오. –

+0

이것도 유용 할 것입니다 : https://wiki.ubuntu.com/DashAsBinSh –