Python子流程。检查_call()不识别pushd和popd
我使用的是Ubuntu 15.04(显然不是随意选择的)和Python3.4.3,我正在尝试执行以下内容Python子流程。检查_call()不识别pushd和popd,python,bash,python-3.x,subprocess,ubuntu-15.04,Python,Bash,Python 3.x,Subprocess,Ubuntu 15.04,我使用的是Ubuntu 15.04(显然不是随意选择的)和Python3.4.3,我正在尝试执行以下内容 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
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)上也做过同样的事情,效果非常好。我还尝试过在Ubuntu15.04和Python3.4.3上执行
subprocess.check_调用(“ls”,shell=True)
(用于健全性检查),效果很好。作为最后一次检查,我在Ubuntu 15.04的Bash中尝试了命令pushd/tmp&&popd
,效果也不错。因此,不知何故,在(我的)使用Python 3.4.3的Ubuntu15.04上,子进程。check_call()
无法识别pushd
和popd
!为什么?您的代码有两个问题。第一个是默认使用的shell是/bin/sh
,它不支持pushd
和popd
。
在您的问题中,您没有提供完整的错误输出,在问题的顶部,您应该看到一行:
/bin/sh: 1: popd: not found
下次请记住发布整个错误消息,而不仅仅是您(错误地)认为相关的部分
您可以通过可执行文件
参数告诉子流程
模块要使用哪个shell来解决此问题:
>>> subprocess.check_call('pushd ~', shell=True, executable='/bin/bash')
~ ~
0
第二个问题是,即使这样,如果使用多个check\u调用
调用,也会出现错误:
>>> 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
现在的事实是,如果您想从python中以这种方式使用pushd
和popd
。。。它们是无用的。这是因为您可以通过cwd
参数指定当前工作目录,因此您可以从python跟踪工作目录堆栈,而无需依赖pushd
和popd
:
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')
替换为pushd('xxx')
,将检查调用('popd')
替换为popd
,并使用运行命令(…)
代替检查调用(…)
正如您所建议的,更优雅的解决方案是使用上下文管理器:
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)
用作:
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 '~'
您的代码有两个问题。第一个是默认使用的shell是
/bin/sh
,它不支持pushd
和popd
。
在您的问题中,您没有提供完整的错误输出,在问题的顶部,您应该看到一行:
/bin/sh: 1: popd: not found
下次请记住发布整个错误消息,而不仅仅是您(错误地)认为相关的部分
您可以通过可执行文件
参数告诉子流程
模块要使用哪个shell来解决此问题:
>>> subprocess.check_call('pushd ~', shell=True, executable='/bin/bash')
~ ~
0
第二个问题是,即使这样,如果使用多个check\u调用
调用,也会出现错误:
>>> 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
现在的事实是,如果您想从python中以这种方式使用pushd
和popd
。。。它们是无用的。这是因为您可以通过cwd
参数指定当前工作目录,因此您可以从python跟踪工作目录堆栈,而无需依赖pushd
和popd
:
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')
替换为pushd('xxx')
,将检查调用('popd')
替换为popd
,并使用运行命令(…)
代替检查调用(…)
正如您所建议的,更优雅的解决方案是使用上下文管理器:
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)
用作:
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 '~'
我现在编辑了我的问题。对不起,我早早犯了一个错误。我知道
check\u call()
会产生一个新的shell。问题不在于调用pushd
后调用popd
;实际上,pushd本身就是如此。@Ray根据您的更新,Bakuriu回答的关键部分是shell不是bash,因此没有可用的pushd。在Ubuntu上试着启动sh并做一个pushd。@Ray我已经重新组织了我的答案,以便更清楚。另外:如果用python编写,IMHO pushd和popd是无用的,只需使用字符串列表作为堆栈,并将正确的cwd=
参数传递给子进程调用。谢谢@Bakuriu。我没有提供完整的错误输出,因为我在Jupyter笔记本中运行它,它没有像普通Python shell那样输出那么多错误消息。如果我使用了普通的Python shell,我可能会注意到它。@Bakuriu我也同意你的观点,即pushd
和popd
应该被更具Python风格的东西所取代,我想实现一个名为pushd
的上下文类,其中包含\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu和,以便使用with语句。但是我写了一些快速而肮脏的管理内容,需要大量的Python,这个问题引起了我的好奇心。我现在编辑了我的问题。对不起,我早早犯了一个错误。我知道check\u call()
会产生一个新的shell。问题不在于调用pushd
后调用popd
;实际上,pushd本身就是如此。@Ray根据您的更新,Bakuriu回答的关键部分是shell不是bash,因此没有可用的pushd。在Ubuntu上试着启动sh并做一个pushd。@Ray我已经重新组织了我的答案,以便更清楚。另外:如果用python编写,IMHO pushd和popd是无用的,只需使用字符串列表作为堆栈,并将正确的cwd=
参数传递给子进程调用。谢谢@Bakuriu。我没有提供完整的错误输出,因为我在Jupyter笔记本中运行它,它没有像普通Python shell那样输出那么多错误消息。如果我使用了普通的Python shell,我可能会注意到它。@Bakuriu我也同意你的观点,即pushd
和popd
应该被更具Python风格的东西所取代,我正在考虑一个名为pushd
的上下文类