在长子进程调用(python)中使用PIPE并不起作用

时间:2014-06-25 13:57:43

标签: python subprocess pipe popen sudo

我正在尝试执行以下命令(通过python脚本下载Caliber):

sudo -v&& wget -nv -O- https://raw.githubusercontent.com/kovidgoyal/calibre/master/setup/linux-installer.py | sudo python -c“import sys; main = lambda:sys.stderr.write('Download failed \ n'); exec(sys.stdin.read()); main()”

关于如何PIPE的一些答案,我一直这样做:

import subprocess
from subprocess import Popen, PIPE
wget = subprocess.Popen(["sudo -v wget -nv -O- https://raw.githubusercontent.com/kovidgoyal/calibre/master/setup/linux-installer.py"], stdout=PIPE) 
run = subprocess.Popen(["sudo python -c "import sys; exec(sys.stdin.read()); main()""], stdin=wget.stdout)

我尝试过改变很多东西但是没有用。这里有太多错误。谁能纠正这个?提前谢谢了。

我得到的只是第一个

2 个答案:

答案 0 :(得分:1)

如果您有参数,则需要将其分解为列表,例如

wget = subprocess.Popen(["wget -nv -O- https://raw.githubusercontent.com/kovidgoyal/calibre/master/setup/linux-installer.py"]) 

(**No such file or directory** error, because it looks for that whole string as a command/file)

需要成为:

subprocess.Popen(['wget', '-nv', '-O-', 'https://raw.githubusercontent.com/kovidgoyal/calibre/master/setup/linux-installer.py'])
<subprocess.Popen object at 0x10e203950>

您也可以使用shlex.split()为您分割命令,例如

>>> import shlex
>>> shlex.split('wget -nv -O- https://raw.githubusercontent.com/kovidgoyal/calibre/master/setup/linux-installer.py')
['wget', '-nv', '-O-', 'https://raw.githubusercontent.com/kovidgoyal/calibre/master/setup/linux-installer.py']

参考。 https://docs.python.org/2/library/subprocess.html#popen-constructor

你也有"sudo python -c "import sys; exec(sys.stdin.read()); main()"",我认为这是不可接受的语法,因为你在引号内引用了引号(内部引用了第一个引号),所以请用单引号代替'sudo python -c "import sys; exec(sys.stdin.read()); main()"',这样你就不必逃避内部的报价!

答案 1 :(得分:0)

为避免在命令中转义引号,您可以使用三引号:

from subprocess import check_call

check_call(r'''# http://calibre-ebook.com/download_linux
  sudo -v &&
  wget -nv -O- https://raw.githubusercontent.com/kovidgoyal/calibre/master/setup/linux-installer.py |
  sudo python -c "import sys; main=lambda:sys.stderr.write('Download failed\n'); exec(sys.stdin.read()); main()"
''', shell=True)

shell=True导致第一个参数被解释为shell命令。

原则上,您可以简化命令:

#!/usr/bin/env python3
import sys
from subprocess import check_call
from urllib.request import urlretrieve

# http://calibre-ebook.com/download_linux
path, _ = urlretrieve('https://raw.githubusercontent.com/kovidgoyal/calibre/master/setup/linux-installer.py')
check_call(['sudo', sys.executable, path])

但它可能会产生微妙的安全隐患,例如,urlretrieve()可能会跳过服务器ssl证书验证。