2016-08-03 6 views
0

私はUbuntu 15.04(Python 3.4.3)と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)でも同じことを試みましたが、完全に機能します。私はまた、Ubuntu 15.04 Python 3.4.3(サニティチェック用)でsubprocess.check_call("ls", shell=True)を実行しようとしましたが、正常に動作します。最後の健全性チェックとして、私はUbuntu 15.04のBashでコマンドpushd /tmp && popdを試しましたが、これもうまくいきます。だから、どういうわけか、(私の)Ubuntu 15.04 Python 3.4.3で、subprocess.check_call()pushdpopdを認識しません!どうして?

答えて

3

コードに2つの問題があります。最初は、デフォルトで使用されるシェルが/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と呼ばれます。あなたのpythonからそのようにpushdpopdを使用して考えた場合、

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

今事実がある:あなたが単一の呼び出しでpushdpopdを結合しようとした場合、彼らは仕事をこと

注意。 ..彼らは役に立たないです。あなたはcwd引数を経て現在の作業ディレクトリを指定することができ、そしてあなたが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')を交換してください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の答えの重要な部分は、シェルがbashではないので利用可能なpushdがないということです。 Ubuntuでshを起動してpushdしようとします。 –

+0

これはあまりにも有用であることを証明し得る:https://wiki.ubuntu.com/DashAsBinSh –

関連する問題