[英]Running Bash commands in Python
On my local machine, I run a python script which contains this line在我的本地机器上,我运行了一个包含这一行的 python 脚本
bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
os.system(bashCommand)
This works fine.这工作正常。
Then I run the same code on a server and I get the following error message然后我在服务器上运行相同的代码,我收到以下错误消息
'import site' failed; use -v for traceback
Traceback (most recent call last):
File "/usr/bin/cwm", line 48, in <module>
from swap import diag
ImportError: No module named swap
So what I did then is I inserted a print bashCommand
which prints me than the command in the terminal before it runs it with os.system()
.所以我当时所做的是我插入了一个
print bashCommand
,它比终端中的命令打印我,然后它使用os.system()
运行它。
Of course, I get again the error (caused by os.system(bashCommand)
) but before that error it prints the command in the terminal.当然,我再次收到错误(由
os.system(bashCommand)
引起),但在该错误之前它会在终端中打印命令。 Then I just copied that output and did a copy paste into the terminal and hit enter and it works...然后我只是复制了 output 并将复制粘贴到终端并按回车,它可以工作......
Does anyone have a clue what's going on?有谁知道发生了什么?
Don't use os.system
.不要使用
os.system
。 It has been deprecated in favor of subprocess .它已被弃用,取而代之的是subprocess 。 From the docs : "This module intends to replace several older modules and functions:
os.system
, os.spawn
".来自文档:“这个模块打算替换几个旧模块和功能:
os.system
, os.spawn
”。
Like in your case:就像你的情况一样:
import subprocess
bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()
To somewhat expand on the earlier answers here, there are a number of details which are commonly overlooked.为了稍微扩展这里的早期答案,有一些通常被忽视的细节。
subprocess.run()
over subprocess.check_call()
and friends over subprocess.call()
over subprocess.Popen()
over os.system()
over os.popen()
subprocess.run()
() 而不是 subprocess.check_call( subprocess.check_call()
和朋友喜欢subprocess.call()
os.system()
subprocess.Popen()
不是 os.system() 而不是os.popen()
text=True
, aka universal_newlines=True
.text=True
,又名universal_newlines=True
。shell=True
or shell=False
and how it changes quoting and the availability of shell conveniences.shell=True
或shell=False
的含义以及它如何更改引用和 shell 便利的可用性。sh
and Bashsh
和 Bash 之间的区别 These topics are covered in some more detail below.下面将更详细地介绍这些主题。
subprocess.run()
or subprocess.check_call()
subprocess.run()
或subprocess.check_call()
The subprocess.Popen()
function is a low-level workhorse but it is tricky to use correctly and you end up copy/pasting multiple lines of code ... which conveniently already exist in the standard library as a set of higher-level wrapper functions for various purposes, which are presented in more detail in the following. subprocess.Popen()
函数是一个低级的主力,但正确使用它很棘手,你最终会复制/粘贴多行代码......这些代码已经作为一组更高级别的包装器方便地存在于标准库中用于各种目的的功能,下面将更详细地介绍。
Here's a paragraph from the documentation :这是文档中的一段:
The recommended approach to invoking subprocesses is to use the
run()
function for all use cases it can handle.调用子流程的推荐方法是对它可以处理的所有用例使用
run()
函数。 For more advanced use cases, the underlyingPopen
interface can be used directly.对于更高级的用例,可以直接使用底层的
Popen
接口。
Unfortunately, the availability of these wrapper functions differs between Python versions.不幸的是,这些包装函数的可用性因 Python 版本而异。
subprocess.run()
was officially introduced in Python 3.5. subprocess.run()
在 Python 3.5 中正式引入。 It is meant to replace all of the following.subprocess.check_output()
was introduced in Python 2.7 / 3.1. subprocess.check_output()
在 Python 2.7 / 3.1 中引入。 It is basically equivalent to subprocess.run(..., check=True, stdout=subprocess.PIPE).stdout
subprocess.run(..., check=True, stdout=subprocess.PIPE).stdout
subprocess.check_call()
was introduced in Python 2.5. subprocess.check_call()
是在 Python 2.5 中引入的。 It is basically equivalent to subprocess.run(..., check=True)
subprocess.run(..., check=True)
subprocess.call()
was introduced in Python 2.4 in the original subprocess
module ( PEP-324 ). subprocess.call()
是在 Python 2.4 的原始subprocess
模块 ( PEP-324 ) 中引入的。 It is basically equivalent to subprocess.run(...).returncode
subprocess.run(...).returncode
subprocess.Popen()
subprocess.Popen()
The refactored and extended subprocess.run()
is more logical and more versatile than the older legacy functions it replaces.重构和扩展的
subprocess.run()
比它取代的旧的遗留函数更符合逻辑和更通用。 It returns a CompletedProcess
object which has various methods which allow you to retrieve the exit status, the standard output, and a few other results and status indicators from the finished subprocess.它返回一个
CompletedProcess
对象,该对象具有多种方法,允许您从已完成的子流程中检索退出状态、标准输出以及一些其他结果和状态指示符。
subprocess.run()
is the way to go if you simply need a program to run and return control to Python.如果您只需要一个程序来运行并将控制权返回给 Python,那么
subprocess.run()
就是要走的路。 For more involved scenarios (background processes, perhaps with interactive I/O with the Python parent program) you still need to use subprocess.Popen()
and take care of all the plumbing yourself.对于更多涉及的场景(后台进程,可能与 Python 父程序的交互式 I/O),您仍然需要使用
subprocess.Popen()
并自己处理所有管道。 This requires a fairly intricate understanding of all the moving parts and should not be undertaken lightly.这需要对所有活动部件有相当复杂的了解,不应轻率地进行。 The simpler
Popen
object represents the (possibly still-running) process which needs to be managed from your code for the remainder of the lifetime of the subprocess.更简单的
Popen
对象表示(可能仍在运行的)进程,需要在子进程的剩余生命周期内从您的代码中进行管理。
It should perhaps be emphasized that just subprocess.Popen()
merely creates a process.或许应该强调一下,只是
subprocess.Popen()
只是创建一个进程。 If you leave it at that, you have a subprocess running concurrently alongside with Python, so a "background" process.如果你把它留在那里,你就会有一个子进程与 Python 一起同时运行,因此是一个“后台”进程。 If it doesn't need to do input or output or otherwise coordinate with you, it can do useful work in parallel with your Python program.
如果它不需要输入或输出或以其他方式与您协调,它可以与您的 Python 程序并行执行有用的工作。
os.system()
and os.popen()
os.system()
和os.popen()
Since time eternal (well, since Python 2.5) theos
module documentation has contained the recommendation to prefer subprocess
over os.system()
:自永恒以来(好吧,自 Python 2.5 起),
os
模块文档包含了更喜欢subprocess
而不是os.system()
的建议:
The
subprocess
module provides more powerful facilities for spawning new processes and retrieving their results;subprocess
模块提供了更强大的工具来生成新进程并检索它们的结果; using that module is preferable to using this function.使用该模块优于使用此功能。
The problems with system()
are that it's obviously system-dependent and doesn't offer ways to interact with the subprocess. system()
的问题在于它显然依赖于系统,并且不提供与子进程交互的方法。 It simply runs, with standard output and standard error outside of Python's reach.它只是运行,标准输出和标准错误超出了 Python 的范围。 The only information Python receives back is the exit status of the command (zero means success, though the meaning of non-zero values is also somewhat system-dependent).
Python 收到的唯一信息是命令的退出状态(零表示成功,尽管非零值的含义在某种程度上也取决于系统)。
PEP-324 (which was already mentioned above) contains a more detailed rationale for why os.system
is problematic and how subprocess
attempts to solve those issues. PEP-324 (上面已经提到过)包含更详细的理由说明
os.system
为何存在问题以及subprocess
进程如何尝试解决这些问题。
os.popen()
used to be even more strongly discouraged : os.popen()
曾经更加不鼓励:
Deprecated since version 2.6: This function is obsolete.
2.6 版后已弃用:此功能已过时。 Use the
subprocess
module.使用
subprocess
模块。
However, since sometime in Python 3, it has been reimplemented to simply use subprocess
, and redirects to the subprocess.Popen()
documentation for details.然而,从 Python 3 的某个时候开始,它已被重新实现为简单地使用
subprocess
,并重定向到subprocess.Popen()
文档以获取详细信息。
check=True
check=True
You'll also notice that subprocess.call()
has many of the same limitations as os.system()
.您还会注意到
os.system()
与 os.system( subprocess.call()
有许多相同的限制。 In regular use, you should generally check whether the process finished successfully, which subprocess.check_call()
and subprocess.check_output()
do (where the latter also returns the standard output of the finished subprocess).在日常使用中,一般应该检查进程是否成功完成,
subprocess.check_call()
和subprocess.check_output()
是做什么的(后者也返回完成的子进程的标准输出)。 Similarly, you should usually use check=True
with subprocess.run()
unless you specifically need to allow the subprocess to return an error status.同样,您通常应该将
check=True
与subprocess.run()
一起使用,除非您特别需要允许子流程返回错误状态。
In practice, with check=True
or subprocess.check_*
, Python will throw a CalledProcessError
exception if the subprocess returns a nonzero exit status.在实践中,使用
check=True
或 subprocess.check_ subprocess.check_*
,如果子进程返回非零退出状态,Python 将抛出CalledProcessError
异常。
A common error with subprocess.run()
is to omit check=True
and be surprised when downstream code fails if the subprocess failed. subprocess.run()
的一个常见错误是省略check=True
并在子进程失败时下游代码失败时感到惊讶。
On the other hand, a common problem with check_call()
and check_output()
was that users who blindly used these functions were surprised when the exception was raised eg when grep
did not find a match.另一方面,
check_call()
和check_output()
的一个常见问题是,当出现异常时,例如当grep
找不到匹配项时,盲目使用这些函数的用户会感到惊讶。 (You should probably replace grep
with native Python code anyway, as outlined below.) (无论如何,您可能应该用本机 Python 代码替换
grep
,如下所述。)
All things counted, you need to understand how shell commands return an exit code, and under what conditions they will return a non-zero (error) exit code, and make a conscious decision how exactly it should be handled.所有的事情都算在内,您需要了解 shell 命令如何返回退出代码,以及在什么情况下它们将返回非零(错误)退出代码,并有意识地决定应该如何处理它。
text=True
aka universal_newlines=True
text=True
aka universal_newlines=True
Since Python 3, strings internal to Python are Unicode strings.从 Python 3 开始,Python 内部的字符串是 Unicode 字符串。 But there is no guarantee that a subprocess generates Unicode output, or strings at all.
但是不能保证子进程会生成 Unicode 输出,或者根本不会生成字符串。
(If the differences are not immediately obvious, Ned Batchelder's Pragmatic Unicode is recommended, if not outright obligatory, reading. There is a 36-minute video presentation behind the link if you prefer, though reading the page yourself will probably take significantly less time.) (如果差异不是很明显,建议阅读 Ned Batchelder 的Pragmatic Unicode ,如果不是完全强制性的话。如果您愿意,链接后面有一个 36 分钟的视频演示,尽管您自己阅读该页面可能会花费更少的时间。 )
Deep down, Python has to fetch a bytes
buffer and interpret it somehow.在内心深处,Python 必须获取一个
bytes
缓冲区并以某种方式对其进行解释。 If it contains a blob of binary data, it shouldn't be decoded into a Unicode string, because that's error-prone and bug-inducing behavior - precisely the sort of pesky behavior which riddled many Python 2 scripts, before there was a way to properly distinguish between encoded text and binary data.如果它包含一团二进制数据,则不应将其解码为 Unicode 字符串,因为这是容易出错和引发错误的行为——正是这种令人讨厌的行为使许多 Python 2 脚本百思不得其解,在没有办法之前正确区分编码文本和二进制数据。
With text=True
, you tell Python that you, in fact, expect back textual data in the system's default encoding, and that it should be decoded into a Python (Unicode) string to the best of Python's ability (usually UTF-8 on any moderately up to date system, except perhaps Windows?)使用
text=True
,您告诉 Python 实际上,您希望返回系统默认编码的文本数据,并且应该尽 Python 的能力将其解码为 Python (Unicode) 字符串(通常是 UTF-8中度更新的系统,也许 Windows 除外?)
If that's not what you request back, Python will just give you bytes
strings in the stdout
and stderr
strings.如果这不是您要求的,Python 只会在
stdout
和stderr
字符串中为您提供bytes
字符串。 Maybe at some later point you do know that they were text strings after all, and you know their encoding.也许稍后您确实知道它们毕竟是文本字符串,并且您知道它们的编码。 Then, you can decode them.
然后,您可以对它们进行解码。
normal = subprocess.run([external, arg],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
check=True,
text=True)
print(normal.stdout)
convoluted = subprocess.run([external, arg],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
check=True)
# You have to know (or guess) the encoding
print(convoluted.stdout.decode('utf-8'))
Python 3.7 introduced the shorter and more descriptive and understandable alias text
for the keyword argument which was previously somewhat misleadingly called universal_newlines
. Python 3.7 为关键字参数引入了更短、更具描述性和更易理解的别名
text
,以前被称为universal_newlines
有点误导。
shell=True
vs shell=False
shell=True
与shell=False
With shell=True
you pass a single string to your shell, and the shell takes it from there.使用
shell=True
您将单个字符串传递给您的 shell,然后 shell 从那里获取它。
With shell=False
you pass a list of arguments to the OS, bypassing the shell.使用
shell=False
,您可以绕过 shell 将参数列表传递给操作系统。
When you don't have a shell, you save a process and get rid of a fairly substantial amount of hidden complexity, which may or may not harbor bugs or even security problems.当您没有外壳时,您可以保存一个过程并消除 相当多的隐藏复杂性,这些复杂性可能存在也可能不存在错误甚至安全问题。
On the other hand, when you don't have a shell, you don't have redirection, wildcard expansion, job control, and a large number of other shell features.另一方面,当您没有 shell 时,就没有重定向、通配符扩展、作业控制和大量其他 shell 功能。
A common mistake is to use shell=True
and then still pass Python a list of tokens, or vice versa.一个常见的错误是使用
shell=True
然后仍然向 Python 传递一个标记列表,反之亦然。 This happens to work in some cases, but is really ill-defined and could break in interesting ways.这恰好在某些情况下有效,但实际上定义不明确并且可能以有趣的方式中断。
# XXX AVOID THIS BUG
buggy = subprocess.run('dig +short stackoverflow.com')
# XXX AVOID THIS BUG TOO
broken = subprocess.run(['dig', '+short', 'stackoverflow.com'],
shell=True)
# XXX DEFINITELY AVOID THIS
pathological = subprocess.run(['dig +short stackoverflow.com'],
shell=True)
correct = subprocess.run(['dig', '+short', 'stackoverflow.com'],
# Probably don't forget these, too
check=True, text=True)
# XXX Probably better avoid shell=True
# but this is nominally correct
fixed_but_fugly = subprocess.run('dig +short stackoverflow.com',
shell=True,
# Probably don't forget these, too
check=True, text=True)
The common retort "but it works for me" is not a useful rebuttal unless you understand exactly under what circumstances it could stop working.常见的反驳“但它对我有用”不是一个有用的反驳,除非你确切地了解它在什么情况下会停止工作。
To briefly recap, correct usage looks like简要回顾一下,正确的用法看起来像
subprocess.run("string for 'the shell' to parse", shell=True)
# or
subprocess.run(["list", "of", "tokenized strings"]) # shell=False
If you want to avoid the shell but are too lazy or unsure of how to parse a string into a list of tokens, notice that shlex.split()
can do this for you.如果您想避免使用 shell,但太懒或不确定如何将字符串解析为令牌列表,请注意
shlex.split()
可以为您完成此操作。
subprocess.run(shlex.split("no string for 'the shell' to parse")) # shell=False
# equivalent to
# subprocess.run(["no", "string", "for", "the shell", "to", "parse"])
The regular split()
will not work here, because it doesn't preserve quoting.常规的
split()
在这里不起作用,因为它不保留引用。 In the example above, notice how "the shell"
is a single string.在上面的示例中,请注意
"the shell"
是如何成为单个字符串的。
Very often, the features of the shell can be replaced with native Python code.很多时候,shell 的功能可以用本机 Python 代码替换。 Simple Awk or
sed
scripts should probably just be translated to Python instead.简单的 Awk 或
sed
脚本应该只翻译成 Python。
To partially illustrate this, here is a typical but slightly silly example which involves many shell features.为了部分说明这一点,这里有一个典型但有点愚蠢的例子,它涉及到许多 shell 特性。
cmd = '''while read -r x;
do ping -c 3 "$x" | grep 'min/avg/max'
done <hosts.txt'''
# Trivial but horrible
results = subprocess.run(
cmd, shell=True, universal_newlines=True, check=True)
print(results.stdout)
# Reimplement with shell=False
with open('hosts.txt') as hosts:
for host in hosts:
host = host.rstrip('\n') # drop newline
ping = subprocess.run(
['ping', '-c', '3', host],
text=True,
stdout=subprocess.PIPE,
check=True)
for line in ping.stdout.split('\n'):
if 'min/avg/max' in line:
print('{}: {}'.format(host, line))
Some things to note here:这里需要注意的一些事项:
shell=False
you don't need the quoting that the shell requires around strings.shell=False
您不需要 shell 需要围绕字符串进行引用。 Putting quotes anyway is probably an error. The refactored code also illustrates just how much the shell really does for you with a very terse syntax -- for better or for worse.重构的代码还以非常简洁的语法说明了 shell 真正为您做了多少——无论好坏。 Python says explicit is better than implicit but the Python code is rather verbose and arguably looks more complex than this really is.
Python 说显式优于隐式,但 Python 代码相当冗长,并且可以说看起来比实际情况更复杂。 On the other hand, it offers a number of points where you can grab control in the middle of something else, as trivially exemplified by the enhancement that we can easily include the host name along with the shell command output.
另一方面,它提供了许多点,您可以在其他事情的中间抓住控制权,我们可以轻松地将主机名与 shell 命令输出一起包含在内的增强功能就是一个简单的例子。 (This is by no means challenging to do in the shell, either, but at the expense of yet another diversion and perhaps another process.)
(这绝不是在 shell 中进行的挑战,但是以另一个转移和可能另一个过程为代价。)
For completeness, here are brief explanations of some of these shell features, and some notes on how they can perhaps be replaced with native Python facilities.为了完整起见,这里是对其中一些 shell 功能的简要说明,以及一些关于如何用本机 Python 工具替换它们的注释。
glob.glob()
or very often with simple Python string comparisons like for file in os.listdir('.'): if not file.endswith('.png'): continue
.glob.glob()
代替,或者经常用简单的 Python 字符串比较代替,例如for file in os.listdir('.'): if not file.endswith('.png'): continue
。 Bash has various other expansion facilities like .{png,jpg}
brace expansion and {1..100}
as well as tilde expansion ( ~
expands to your home directory, and more generally ~account
to the home directory of another user) .{png,jpg}
大括号扩展和{1..100}
以及波浪号扩展( ~
扩展至您的主目录,更一般地~account
扩展至另一个用户的主目录)$SHELL
or $my_exported_var
can sometimes simply be replaced with Python variables.$SHELL
或$my_exported_var
这样的 Shell 变量有时可以简单地替换为 Python 变量。 Exported shell variables are available as eg os.environ['SHELL']
(the meaning of export
is to make the variable available to subprocesses -- a variable which is not available to subprocesses will obviously not be available to Python running as a subprocess of the shell, or vice versa. The env=
keyword argument to subprocess
methods allows you to define the environment of the subprocess as a dictionary, so that's one way to make a Python variable visible to a subprocess).os.environ['SHELL']
( export
的含义是使变量可用于子进程 - 子进程不可用的变量显然对于作为子进程运行的 Python 不可用shell,反之亦然。 subprocess
方法的env=
关键字参数允许您将子进程的环境定义为字典,因此这是使 Python 变量对子进程可见的一种方法)。 With shell=False
you will need to understand how to remove any quotes;shell=False
您将需要了解如何删除任何引号; for example, cd "$HOME"
is equivalent to os.chdir(os.environ['HOME'])
without quotes around the directory name.cd "$HOME"
等价于os.chdir(os.environ['HOME'])
目录名称不带引号。 (Very often cd
is not useful or necessary anyway, and many beginners omit the double quotes around the variable and get away with ituntil one day ... ) cd
无论如何都没有用或没有必要,许多初学者省略了变量周围的双引号,直到有一天...... )grep 'foo' <inputfile >outputfile
opens outputfile
for writing and inputfile
for reading, and passes its contents as standard input to grep
, whose standard output then lands in outputfile
. grep 'foo' <inputfile >outputfile
inputfile
outputfile
写入的输出文件和用于读取的输入文件,并将其内容作为标准输入传递给grep
,然后其标准输出位于outputfile
中。 This is not generally hard to replace with native Python code.echo foo | nl
echo foo | nl
runs two subprocesses, where the standard output of echo
is the standard input of nl
(on the OS level, in Unix-like systems, this is a single file handle). echo foo | nl
运行两个子进程,其中echo
的标准输出是nl
的标准输入(在操作系统级别,在类 Unix 系统中,这是单个文件句柄)。 If you cannot replace one or both ends of the pipeline with native Python code, perhaps think about using a shell after all, especially if the pipeline has more than two or three processes (though look at the pipes
module in the Python standard library or a number of more modern and versatile third-party competitors).pipes
模块或更多现代和多才多艺的第三方竞争对手)。ls -l /
is equivalent to 'ls' '-l' '/'
but the quoting around literals is completely optional.ls -l /
等同于'ls' '-l' '/'
但文字周围的引用是完全可选的。 Unquoted strings which contain shell metacharacters undergo parameter expansion, whitespace tokenization and wildcard expansion;sh
and Bashsh
和 Bash 之间的区别subprocess
runs your shell commands with /bin/sh
unless you specifically request otherwise (except of course on Windows, where it uses the value of the COMSPEC
variable). subprocess
使用/bin/sh
运行您的 shell 命令,除非您另有特别要求(当然在 Windows 上除外,它使用COMSPEC
变量的值)。 This means that various Bash-only features like arrays, [[
etc are not available.这意味着数组、
[[
等各种仅限 Bash 的功能不可用。
If you need to use Bash-only syntax, you can pass in the path to the shell as executable='/bin/bash'
(where of course if your Bash is installed somewhere else, you need to adjust the path).如果您需要使用纯 Bash 语法,您可以将 shell 的路径作为
executable='/bin/bash'
传递(当然,如果您的 Bash 安装在其他地方,则需要调整路径)。
subprocess.run('''
# This for loop syntax is Bash only
for((i=1;i<=$#;i++)); do
# Arrays are Bash-only
array[i]+=123
done''',
shell=True, check=True,
executable='/bin/bash')
subprocess
is separate from its parent, and cannot change it subprocess
与其父进程是分开的,并且不能改变它A somewhat common mistake is doing something like一个有点常见的错误是做类似的事情
subprocess.run('cd /tmp', shell=True)
subprocess.run('pwd', shell=True) # Oops, doesn't print /tmp
The same thing will happen if the first subprocess tries to set an environment variable, which of course will have disappeared when you run another subprocess, etc.如果第一个子进程尝试设置环境变量,也会发生同样的事情,当您运行另一个子进程等时,它当然会消失。
A child process runs completely separate from Python, and when it finishes, Python has no idea what it did (apart from the vague indicators that it can infer from the exit status and output from the child process).子进程完全独立于 Python 运行,当它完成时,Python 不知道它做了什么(除了可以从子进程的退出状态和输出推断出的模糊指示符)。 A child generally cannot change the parent's environment;
孩子一般不能改变父母的环境; it cannot set a variable, change the working directory, or, in so many words, communicate with its parent without cooperation from the parent.
它无法设置变量、更改工作目录,或者,换句话说,在没有父级合作的情况下与父级通信。
The immediate fix in this particular case is to run both commands in a single subprocess;在这种特殊情况下的直接解决方法是在单个子进程中运行这两个命令;
subprocess.run('cd /tmp; pwd', shell=True)
though obviously this particular use case isn't very useful;虽然显然这个特定的用例不是很有用; instead, use the
cwd
keyword argument, or simply os.chdir()
before running the subprocess.相反,在运行子进程之前使用
cwd
关键字参数,或者干脆os.chdir()
。 Similarly, for setting a variable, you can manipulate the environment of the current process (and thus also its children) via同样,对于设置变量,您可以通过以下方式操作当前进程(以及其子进程)的环境
os.environ['foo'] = 'bar'
or pass an environment setting to a child process with或将环境设置传递给子进程
subprocess.run('echo "$foo"', shell=True, env={'foo': 'bar'})
(not to mention the obvious refactoring subprocess.run(['echo', 'bar'])
; but echo
is a poor example of something to run in a subprocess in the first place, of course). (更不用说明显的重构
subprocess.run(['echo', 'bar'])
;但是echo
是首先在子进程中运行的一个糟糕的例子,当然)。
This is slightly dubious advice;这是一个有点可疑的建议; there are certainly situations where it does make sense or is even an absolute requirement to run the Python interpreter as a subprocess from a Python script.
在某些情况下,将 Python 解释器作为 Python 脚本的子进程运行是有意义的,甚至是绝对要求。 But very frequently, the correct approach is simply to
import
the other Python module into your calling script and call its functions directly.但很多时候,正确的方法是将另一个 Python 模块
import
到您的调用脚本中并直接调用它的函数。
If the other Python script is under your control, and it isn't a module, consider turning it into one .如果另一个 Python 脚本在您的控制之下,并且它不是一个模块,请考虑将其转换为一个. (This answer is too long already so I will not delve into details here.)
(这个答案已经太长了,所以我不会在这里深入细节。)
If you need parallelism, you can run Python functions in subprocesses with the multiprocessing
module.如果您需要并行性,您可以使用
multiprocessing
模块在子进程中运行 Python 函数。 There is also threading
which runs multiple tasks in a single process (which is more lightweight and gives you more control, but also more constrained in that threads within a process are tightly coupled, and bound to a single GIL .)还有在单个进程中运行多个任务的
threading
(它更轻量级并为您提供更多控制,但也更受限制,因为进程中的线程紧密耦合,并绑定到单个GIL 。)
Call it with subprocess用子进程调用它
import subprocess
subprocess.Popen("cwm --rdf test.rdf --ntriples > test.nt")
The error you are getting seems to be because there is no swap module on the server, you should install swap on the server then run the script again你得到的错误似乎是因为服务器上没有交换模块,你应该在服务器上安装交换然后再次运行脚本
It is possible you use the bash program, with the parameter -c for execute the commands:您可以使用带有参数 -c 的 bash 程序来执行命令:
bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
output = subprocess.check_output(['bash','-c', bashCommand])
You can use subprocess
, but I always felt that it was not a 'Pythonic' way of doing it.您可以使用
subprocess
,但我一直觉得这不是一种“Pythonic”的方式。 So I created Sultan (shameless plug) that makes it easy to run command line functions.所以我创建了 Sultan(无耻插件),可以轻松运行命令行功能。
https://github.com/aeroxis/sultan https://github.com/aeroxis/sultan
According to the error you are missing a package named swap on the server.根据错误,您在服务器上缺少一个名为swap的包。 This
/usr/bin/cwm
requires it.这个
/usr/bin/cwm
需要它。 If you're on Ubuntu/Debian, install python-swap
using aptitude.如果您使用的是 Ubuntu/Debian,请使用 aptitude 安装
python-swap
。
Also you can use 'os.popen'.你也可以使用'os.popen'。 Example:
例子:
import os
command = os.popen('ls -al')
print(command.read())
print(command.close())
Output:输出:
total 16
drwxr-xr-x 2 root root 4096 ago 13 21:53 .
drwxr-xr-x 4 root root 4096 ago 13 01:50 ..
-rw-r--r-- 1 root root 1278 ago 13 21:12 bot.py
-rw-r--r-- 1 root root 77 ago 13 21:53 test.py
None
To run the command without a shell, pass the command as a list and implement the redirection in Python using [subprocess]
:要在没有 shell 的情况下运行命令,请将命令作为列表传递并使用
[subprocess]
在 Python 中实现重定向:
#!/usr/bin/env python
import subprocess
with open('test.nt', 'wb', 0) as file:
subprocess.check_call("cwm --rdf test.rdf --ntriples".split(),
stdout=file)
Note: no > test.nt
at the end.注意:最后没有
> test.nt
stdout=file
implements the redirection. stdout=file
实现重定向。
To run the command using the shell in Python, pass the command as a string and enable shell=True
:要在 Python 中使用 shell 运行命令,请将命令作为字符串传递并启用
shell=True
:
#!/usr/bin/env python
import subprocess
subprocess.check_call("cwm --rdf test.rdf --ntriples > test.nt",
shell=True)
Here's the shell is responsible for the output redirection ( > test.nt
is in the command).这是负责输出重定向的shell(
> test.nt
在命令中)。
To run a bash command that uses bashisms, specify the bash executable explicitly eg, to emulate bash process substitution :要运行使用 bashisms 的 bash 命令,请明确指定 bash 可执行文件,例如,模拟 bash 进程替换:
#!/usr/bin/env python
import subprocess
subprocess.check_call('program <(command) <(another-command)',
shell=True, executable='/bin/bash')
subprocess.Popen()
is prefered over os.system()
as it offers more control and visibility. os.system()
subprocess.Popen()
它提供了更多的控制和可见性。 However, If you find subprocess.Popen()
too verbose or complex, peasyshell
is a small wrapper I wrote above it, which makes it easy to interact with bash from Python.但是,如果您发现 subprocess.Popen
subprocess.Popen()
过于冗长或复杂, peasyshell
是我在上面编写的一个小型包装器,它可以轻松地从 Python 与 bash 交互。
https://github.com/davidohana/peasyshell https://github.com/davidohana/peasyshell
The pythonic way of doing this is using subprocess.Popen
这样做的pythonic方法是使用
subprocess.Popen
subprocess.Popen
takes a list where the first element is the command to be run followed by any command line arguments. subprocess.Popen
接受一个列表,其中第一个元素是要运行的命令,后跟任何命令行参数。
As an example:举个例子:
import subprocess
args = ['echo', 'Hello!']
subprocess.Popen(args) // same as running `echo Hello!` on cmd line
args2 = ['echo', '-v', '"Hello Again"']
subprocess.Popen(args2) // same as running 'echo -v "Hello Again!"` on cmd line
copy paste this:复制粘贴这个:
def run_bash_command(cmd: str) -> Any:
import subprocess
process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
output, error = process.communicate()
if error:
raise Exception(error)
else:
return output
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.