【问题标题】:Python subprocess help - Can't use shell=true [duplicate]Python子进程帮助-不能使用shell = true [重复]
【发布时间】:2017-03-01 08:48:15
【问题描述】:

我在这里绞尽脑汁,试图在不使用 shell=true 的情况下用 python 做一个简单的函数,但没有得到我需要的结果。我在 Linux 上使用 python 2.7。

我已经尝试了多种方法来做到这一点。如果我像这样使用 shell=true 它工作正常:

import subprocess as s

var1 = s.call("echo $HOME", shell=True)

import subprocess as s

var1 = s.check_output("echo $HOME", shell=True)

都返回

/home/myhost

... 应该是这样,但我尝试的其他一切都失败了。在大多数情况下,它似乎将我的变量作为字符串而不是命令传递。

这些是我通过各种方法得到的结果:

import subprocess as s

print var1

返回

myhost@me:~/Desktop$ python home_test.py 
  File "home_test.py", line 42, in <module>
    main()
  File "home_test.py", line 11, in main
    my_test()
  File "home_test.py", line 16, in check_auth
    var1 = s.check_output("echo $HOME")
  File "/usr/lib/python2.7/subprocess.py", line 567, in check_output
    process = Popen(stdout=PIPE, *popenargs, **kwargs)
  File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

然后我尝试了这个:

import subprocess as s

var1 = s.Popen(['echo', '$HOME'], stdout=s.PIPE) 

print var1

返回

myhost@me:~/Desktop$ python home_test.py 
<subprocess.Popen object at 0x7f297ebcbf90>
myhost@me:~/Desktop$echo: write error: Broken pipe

然后这个:

import subprocess as s

cmd1 = '$HOME'
var1 = s.Popen(['/bin/echo', cmd1], stdout=s.PIPE)

print var1

返回

('$Home\n', None)

还有这个

import subprocess as s

cmd1 = 'HOME'
var1 = s.Popen(['/bin/echo', cmd1], stdout=s.PIPE)
print var1

返回

myhost@me:~/Desktop$ python home_test.py 
('Home\n', None)

找到一些说使用 os... 的文档也失败了,在发现 2.6 中已弃用此功能后,这并不奇怪。

import os

var1 = os.popen('echo $HOME')
print var1

返回

<open file 'echo $HOME', mode 'r' at 0x7f1c6b26f6f0>
sh: echo: I/O error

然后是我的最后一次尝试(实际上还有更多……但我们就这样吧)

import subprocess as s

var1= s.Popen(["echo", "$HOME"], stdout=s.PIPE).communicate()[0] 

print var1

返回:

myhost@me:~/Desktop$ python home_test.py 
$HOME

有人可以指出我正确的方向吗?我花了一整天的时间摆弄这个,我需要帮助。预先感谢您提供的任何帮助。

【问题讨论】:

  • var1 = s.Popen(['echo', '$HOME'], stdout=s.PIPE) 中,只有第一个数组元素被视为脚本。后续数组元素是该脚本的参数。
  • ...顺便说一句,你真正的用例是什么?一般来说,使用shell=True 是错误的;如果没有足够(大量!)谨慎使用,它会引入安全错误,并且不会通过让 Python 更冗长来做任何你不能做的事情。

标签: python linux python-2.7 shell subprocess


【解决方案1】:

让我们从答案开始

导入操作系统 home = os.environ['HOME'] 打印(首页)

现在谈谈你的尝试和结果。您的主要问题(除了一些随机错误)是 $HOME 被 shell 替换为环境变量的值。没有 shell 参数扩展 $HOME 只是一个字符串,这就是你得到的。

【讨论】:

  • 感谢您的成功。我不知道为什么我没有想到这一点。可能是因为我在尝试使用子进程时撞墙了。
  • 你的主要问题是你试图在不使用 shell 的情况下进行 shell 变量扩展 :)
  • @shellsbelles:作为一项规则,绝大多数简单的 shell 实用程序在 Python 中都有更好的(或至少更低的开销)等价物。即使在subprocessing shell 实用程序出现更快的情况下(例如,从.gz 文件中读取压缩数据表面上更快),这通常只是因为subprocess“免费”执行并行性(并且在@987654326 @module 的情况,在某些版本上,这是因为它们默认没有缓冲,io.BufferedReader wrapping 会修复它);如果您对 Python 等效代码进行线程化或并行处理,它不会损失太多。
  • 几个例子:读取环境最好用os.environ,移动和复制文件用shutil,处理压缩数据用gzip/bzip2/lzma模块,ls 没有 globbing 变为 os.listdiros.scandir 在现代 Python 上以获得更好的性能)或 glob 模块用于 globbing 行为,find 变为 os.walk,等等。
【解决方案2】:

听起来您真的只想获取环境变量的值。 os.getenv('HOME') 应该为你做到这一点。

【讨论】:

  • 谢谢,但是这不起作用,我把结果放在了 cmets
  • 没关系,我有错字。这也奏效了。谢谢你们俩。
  • 切向警告:作为一项规则,最好只使用os.environ 并禁止getenv/putenv 以保持一致性。具体来说,如果你改变环境就会出现问题。调用putenv 不会改变os.environ,但变异os.environ 也会改变putenv(如果支持)。此外,getenvputenv 并非在所有操作系统上都可用(尽管不可否认,只有少数类似 UNIX 的版本不支持 AFAICT),而始终支持 os.environ
【解决方案3】:

提到os.environ['HOME'] 的答案是正确的,但它可能不是您想要的可移植性。不能保证设置了HOME(按照惯例,不是必需的;用户可以删除它,shell 可以选择不设置它,等等)。如果你最终想要移植到 Windows,那不是它的名字。如果你想要用户的主目录,不要直接检查环境,而是使用os.path.expanduser使用更智能的主目录查找逻辑:

import os.path

home = os.path.expanduser('~')

即使HOME 未定义,这也可以工作,并泛化为查找其他用户的主目录 (os.path.expanduser('~someotheruser'))。

在 Python 3.5+ 中,您还可以use pathlib.Path.home() to get a Path object representing the home directory

另外,如果你需要用一堆环境变量替换来扩展一个字符串,你可能想看看os.path.expandvars,它将环境查找和字符串格式化作为一个单一的操作。

【讨论】:

    猜你喜欢
    • 2015-08-30
    • 1970-01-01
    • 2017-02-09
    • 2016-11-19
    • 1970-01-01
    • 2012-12-20
    • 2018-08-13
    • 1970-01-01
    • 2021-05-08
    相关资源
    最近更新 更多