为啥 Python 子进程中的 ln 在正常命令行成功时失败?

Posted

技术标签:

【中文标题】为啥 Python 子进程中的 ln 在正常命令行成功时失败?【英文标题】:Why does ln from Python subprocess fail while it succeeds from normal command line?为什么 Python 子进程中的 ln 在正常命令行成功时失败? 【发布时间】:2015-05-27 14:54:47 【问题描述】:

正如标题所说:

>>> from subprocess import check_output
>>> check_output(['ln', '~/other_folder/src/models/sc_models.py', './src/models/sc_models.py'])
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 573, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
CalledProcessError: Command '['ln', '~/other_folder/src/models/sc_models.py', './src/models/sc_models.py']' returned non-zero exit status 1
>>> exit()
$ ln ~/other_folder/src/models/sc_models.py ./src/models/sc_models.py
$

这怎么可能?它如何从命令行成功,但从 Python 子进程调用失败?

欢迎所有提示!

【问题讨论】:

尝试将shell=True 添加到您的 check_output 命令中 不过,不要将shell=True 与参数列表结合使用。 【参考方案1】:

你需要使用os.path.expanduser:

在 Unix 和 Windows 上,返回带有 ~ 或 ~user 的初始组件的参数,替换为该用户的主目录。

import os

os.path.expanduser('~/other_folder/src/models/sc_models.py')

In [2]: os.path.expanduser("~")
Out[2]: '/home/padraic'

Python 正在您的 cwd 中寻找一个名为 ~ 的目录,这显然失败了。当您从 bash 运行代码时,~ 被扩展,除非您使用 shell=True,其中命令将被传递到 shell 并且 shell 会扩展波浪号,那么您将需要使用 os.path.expanduser 或传递整个路径,即 /home/user/other_folder……我会坚持使用 shell=False 和os.path.expanduser("~")

【讨论】:

注意:即使您要添加 shell=True,问题中的代码也不起作用,因为只有第一个列表项作为 shell 命令执行,其余的被解释为 shell 的参数POSIX。换句话说:不要同时使用列表参数和shell=True,而是传递一个字符串,或者(更好)不要使用shell=True:正如您所展示的那样,在这里调用os.path.expanduser('~/...') 就足够了。跨度> @J.F.Sebastian,那为什么check_call(["ls","~/"],shell=True) 有效? 你明白sh -c 'cmd arg1'(正确)和sh -c 'cmd' arg1(错误)的区别吗?例如,请参阅bugs.python.org/issue7839

以上是关于为啥 Python 子进程中的 ln 在正常命令行成功时失败?的主要内容,如果未能解决你的问题,请参考以下文章

Python 子进程中的 ffmpeg - 无法为“管道:”找到合适的输出格式

为啥 Python 不能通过子进程执行 java.exe?

使用Python子进程中的Vim编辑临时文件在Mac OS上无法正常工作

Python子进程 - 在新文件中保存输出

通过子进程或其他方法的 Python 速度命令行调用

通过 Python 子进程运行时使用仪器获取 iDevices 卡住了