python(Windows)中的多个shell命令
我正在windows计算机上工作,我想在shell中设置一个变量,并想将其与另一个shell命令一起使用,如:python(Windows)中的多个shell命令,python,windows,python-3.x,subprocess,popen,Python,Windows,Python 3.x,Subprocess,Popen,我正在windows计算机上工作,我想在shell中设置一个变量,并想将其与另一个shell命令一起使用,如: set variable = abc echo %variable% 我知道我可以使用os.system(com1和com2)来实现这一点,但我也知道,这被认为是“糟糕的风格”,应该可以通过使用子流程模块来实现,但我不知道如何实现。 以下是我到目前为止得到的信息: proc = Popen('set variable=abc', shell=True, stdin=PIPE, std
set variable = abc
echo %variable%
我知道我可以使用os.system(com1和com2)来实现这一点,但我也知道,这被认为是“糟糕的风格”,应该可以通过使用子流程模块来实现,但我不知道如何实现。
以下是我到目前为止得到的信息:
proc = Popen('set variable=abc', shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
proc.communicate(input=b'echo %variable%)
但这两行似乎都不起作用,两个命令都无法执行。此外,如果我键入不存在的命令,我不会得到错误。如何正确执行此操作?
Popen
只能执行一个命令或shell脚本。您可以使用简单地将整个shell脚本作为单个参数提供
要分离不同的命令,请执行以下操作:
proc = Popen('set variable=abc;echo %variable%', shell=True)
>>> proc = Popen(['sh'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
>>> proc.communicate('echo 1; echo 2\n')
('1\n2\n', '')
或者您实际上可以使用多行字符串:
>>> from subprocess import call
>>> call('''echo 1
... echo 2
... ''', shell=True)
1
2
0
最后一个0
是流程的返回代码
communicate
方法用于写入进程的stdin。在您的情况下,该过程在运行set variable
后立即结束,因此对communicate
的调用实际上没有任何作用
您可以生成一个shell,然后使用communicate
编写命令:
proc = Popen('set variable=abc;echo %variable%', shell=True)
>>> proc = Popen(['sh'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
>>> proc.communicate('echo 1; echo 2\n')
('1\n2\n', '')
请注意,communicate
完成后也会关闭流,因此不能多次调用。如果您想要交互式会话,您可以直接写入proc.stdin
并从proc.stdout
读取
顺便说一句:您可以将
env
参数指定为Popen
,因此,根据具体情况,您可能需要改为:
proc = Popen(['echo', '%variable%'], env={'variable': 'abc'})
显然,这将使用
echo
可执行文件,而不是shell内置文件,但它避免使用shell=True
由Popen
启动的shell不会等待其标准输入;set
命令运行,然后shell退出,而不尝试从标准输入中读取任何内容。在本例中,您的命令(从Python脚本的角度来看)是一个单shell脚本,碰巧由两个shell命令组成,而不是一对shell命令。我强烈建议在标题和标记中更明确地说明Windows。在UNIX上,你会得到一个完全不同的答案……不过,一般来说,你所依赖的东西(设置和扩展的shell变量)依赖于拥有一个shell,所以在UNIX世界中,最佳实践是完全重写你正在做的事情,使其完全不依赖于shell变量。这不起作用(对我来说)。如果我键入:proc=Popen('echo abc;echo 123',shell=True)output=proc.communicate()[0]打印(输出),我得到abc;echo123
,因此它不会将其读取为两行/commands@AracKnight>>从子流程导入调用>>>调用('echo 1;echo 2',shell=True)1 2
它对我有效。您应该确切地指定您在问题中使用的代码。另外,您是在Windows还是linux上?
在linux上工作,我不确定powershell/批处理文件是否使用不同的分隔符。但是:您也可以使用多行字符串作为命令调用('echo 1\necho 2',shell=True)
。我在Windows 10 64位上工作。我在第一行将数据库连接的密码设置为环境变量,以便在下一行调用psql并连接到数据库。使用call('echo abc\necho 123',shell=True)
我得到abc
作为输出,所以第二个命令仍然不起作用。@AracKnight如果这是您的用例,我相信您应该按照我最后描述的做:通过env
参数提供env变量,而不是使用shell进行黑客攻击。当我为Popen指定env
参数时,如果不知道变量的确切路径,我就不能再调用psql了psql.exe
,因为我通常从PATH变量运行它,如果它传递了一个env
,它就会被Popen忽略。此外,尽管我可能能够解决我目前的问题,但我真的很想知道这些目标通常是如何实现的,因为我将来可能会遇到类似的问题。