Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
356 views
in Technique[技术] by (71.8m points)

python - 运行shell命令并捕获输出(Running shell command and capturing the output)

I want to write a function that will execute a shell command and return its output as a string , no matter, is it an error or success message.

(我想编写一个函数,该函数将执行shell命令并以字符串形式返回其输出,无论它是错误消息还是成功消息。)

I just want to get the same result that I would have gotten with the command line.

(我只想获得与命令行相同的结果。)

What would be a code example that would do such a thing?

(能做到这一点的代码示例是什么?)

For example:

(例如:)

def run_command(cmd):
    # ??????

print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'
  ask by Silver Light translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The answer to this question depends on the version of Python you're using.

(这个问题的答案取决于您使用的Python版本。)

The simplest approach is to use the subprocess.check_output function:

(最简单的方法是使用subprocess.check_output函数:)

>>> subprocess.check_output(['ls', '-l'])
b'total 0
-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files
'

check_output runs a single program that takes only arguments as input.

(check_output运行一个仅将参数作为输入的程序。)

1 It returns the result exactly as printed to stdout .

(1它返回与打印到stdout完全相同的结果。)

If you need to write input to stdin , skip ahead to the run or Popen sections.

(如果需要将输入写入stdin ,请跳至runPopen部分。)

If you want to execute complex shell commands, see the note on shell=True at the end of this answer.

(如果要执行复杂的Shell命令,请参阅此答案末尾关于shell=True的注释。)

The check_output function works on almost all versions of Python still in wide use (2.7+).

(check_output函数可用于几乎所有仍在广泛使用的Python版本(2.7+)。)

2 But for more recent versions, it is no longer the recommended approach.

(2但对于较新的版本,不再推荐使用此方法。)

Modern versions of Python (3.5 or higher): run (现代版本的Python(3.5或更高版本): run)

If you're using Python 3.5 or higher, and do not need backwards compatibility , the new run function is recommended.

(如果您使用的是Python 3.5或更高版本,并且不需要向后兼容 ,则建议使用新的run函数 。)

It provides a very general, high-level API for the subprocess module.

(它为subprocess模块提供了非常通用的高级API。)

To capture the output of a program, pass the subprocess.PIPE flag to the stdout keyword argument.

(要捕获程序的输出,请将subprocess.PIPE标志传递给stdout关键字参数。)

Then access the stdout attribute of the returned CompletedProcess object:

(然后访问返回的CompletedProcess对象的stdout属性:)

>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0
-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files
'

The return value is a bytes object, so if you want a proper string, you'll need to decode it.

(返回值是一个bytes对象,因此,如果要使用正确的字符串,则需要对其进行decode 。)

Assuming the called process returns a UTF-8-encoded string:

(假设被调用的进程返回一个UTF-8编码的字符串:)

>>> result.stdout.decode('utf-8')
'total 0
-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files
'

This can all be compressed to a one-liner:

(所有这些都可以压缩为单线:)

>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0
-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files
'

If you want to pass input to the process's stdin , pass a bytes object to the input keyword argument:

(如果要将输入传递给进程的stdin ,请将bytes对象传递给input关键字参数:)

>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo
foofoo
'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo
'

You can capture errors by passing stderr=subprocess.PIPE (capture to result.stderr ) or stderr=subprocess.STDOUT (capture to result.stdout along with regular output).

(您可以通过传递stderr=subprocess.PIPE (捕获到result.stderr )或stderr=subprocess.STDOUT (捕获到result.stdout以及常规输出)来捕获错误。)

When security is not a concern, you can also run more complex shell commands by passing shell=True as described in the notes below.

(如果不考虑安全性,您还可以通过传递shell=True来运行更复杂的Shell命令,如下面的注释所述。)

This adds just a bit of complexity, compared to the old way of doing things.

(与旧的处理方式相比,这仅增加了一点复杂性。)

But I think it's worth the payoff: now you can do almost anything you need to do with the run function alone.

(但是我认为值得这样做:现在,您run功能就可以完成几乎所有需要做的事情。)

Older versions of Python (2.7-3.4): check_output (旧版本的Python(2.7-3.4): check_output)

If you are using an older version of Python, or need modest backwards compatibility, you can probably use the check_output function as briefly described above.

(如果您使用的是旧版本的Python,或者需要适度的向后兼容性,则可以使用如上文所述的check_output函数。)

It has been available since Python 2.7.

(自python 2.7开始提供。)

subprocess.check_output(*popenargs, **kwargs)  

It takes takes the same arguments as Popen (see below), and returns a string containing the program's output.

(它采用与Popen相同的参数(请参见下文),并返回一个包含程序输出的字符串。)

The beginning of this answer has a more detailed usage example.

(该答案的开头有一个更详细的用法示例。)

In Python 3.5 and greater, check_output is equivalent to executing run with check=True and stdout=PIPE , and returning just the stdout attribute.

(在Python 3.5及更高版本中, check_output等效于使用check=Truestdout=PIPE执行run ,并仅返回stdout属性。)

You can pass stderr=subprocess.STDOUT to ensure that error messages are included in the returned output -- but in some versions of Python passing stderr=subprocess.PIPE to check_output can cause deadlocks .

(您可以传递stderr=subprocess.STDOUT以确保错误消息包含在返回的输出中-但是在某些版本的Python中,将stderr=subprocess.PIPE check_output传递给check_output可能导致死锁 。)

When security is not a concern, you can also run more complex shell commands by passing shell=True as described in the notes below.

(如果不考虑安全性,您还可以通过传递shell=True来运行更复杂的Shell命令,如下面的注释所述。)

If you need to pipe from stderr or pass input to the process, check_output won't be up to the task.

(如果您需要从stderr进行管道传输或将输入传递给进程,则check_output将无法完成任务。)

See the Popen examples below in that case.

(在这种情况下,请参见下面的Popen示例。)

Complex applications & legacy versions of Python (2.6 and below): Popen (复杂的应用程序和Python的旧版(2.6及更低版本): Popen)

If you need deep backwards compatibility, or if you need more sophisticated functionality than check_output provides, you'll have to work directly with Popen objects, which encapsulate the low-level API for subprocesses.

(如果需要深度向后兼容性,或者需要比check_output提供的功能更复杂的功能,则必须直接使用Popen对象,该对象封装了用于子流程的低级API。)

The Popen constructor accepts either a single command without arguments, or a list containing a command as its first item, followed by any number of arguments, each as a separate item in the list.

(Popen构造函数可以接受不带参数的单个命令 ,也可以接受包含命令的列表作为其第一项,后跟任意数量的参数,每个参数均作为列表中的单独项。)

shlex.split can help parse strings into appropriately formatted lists.

(shlex.split可以帮助将字符串解析为适当格式的列表。)

Popen objects also accept a host of different arguments for process IO management and low-level configuration.

(Popen对象还接受用于进程IO管理和低级配置的许多不同参数 。)

To send input and capture output, communicate is almost always the preferred method.

(要发送输入和捕获输出, communicate几乎总是首选方法。)

As in:

(如:)

output = subprocess.Popen(["mycmd", "myarg"], 
                          stdout=subprocess.PIPE).communicate()[0]

Or

(要么)

>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE, 
...                                    stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo

If you set stdin=PIPE , communicate also allows you to pass data to the process via stdin :

(如果设置stdin=PIPE ,则communicate还允许您通过stdin将数据传递给流程:)

>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
...                           stderr=subprocess.PIPE,
...                           stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo
foofoo
')
>>> print out
foofoo

Note Aaron Hall's answer , which indicates that on some systems, you may need


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...