在Python中执行命令(1)
如果一天中会花费很多时间在终端里输入各种命令,那么你可能需要学会执行一些语句,例如将处理结果重定向,输出到文件或输出给另一个UNIX命令。接下来我们进行一些比较,从而了解一些Bash下执行的命令在Python中是如何执行的。在Bash终端中,键入如下内容:
[ngift@Macintosh-7][H:10701][J:0]# ls -l /tmp/
total 0
-rw-r--r-- 1 ngift wheel 0 Apr 7 00:26 file.txt
而在Python终端中,需要键入的内容如下:
In [2]: import subprocess
In [3]: subprocess.call(["ls","-l ","/tmp/"])
total 0
-rw-r--r-- 1 ngift wheel 0 Apr 7 00:26 file.txt
Out[3]: 0
在上述Ba s h示例中,可以很清晰地看到,仅使用了一个非常简单的l s命令。但对于Python示例则不同,如果之前从没有见过Python代码,Python示例看起来可能会令人觉得有些怪异。你可能会想问“真见鬼,import subprocess究竟是什么意思”?Python之所以强大,原因之一就是Python可以载入其他模块,或包含其他文件,并在新的程序中做到代码复用。如果你比较熟悉Bash中的“sourcing”一个文件,就会发现相似之处。在上例所示的特定情况下,你只需要知道加载了模块subprocess,并且知道使用该模块的语法。我们之后会具体解释subprocess和import是如何工作的,现在直接复制下面的代码即可:
subprocess.call(["some_command", "some_argument",
"another_argument_or_path"])
在Python中,可以就像在Bash中一样使用shell命令。给一点提示:你可以创建Python版本的l s命令。在另一个终端或另一个终端窗口中打开你经常使用的文本编辑器,将上述代码写入到该文件中,且将该文件命名为pyls.py,***使用命令“chmod +x pyls.py”将该文件修改为可执行文件。参见例1-1。
例1-1:
Python包装ls命令#!/usr/bin/env python
#Python wrapper for the ls command
import subprocess
subprocess.call(["ls","-l"])
如果现在运行该脚本,将获得与在命令行使用ls -l命令完全相同的结果,如下所示:
[ngift@Macintosh-7][H:10746][J:0]# ./pyls.py
total 8
-rwxr-xr-x 1 ngift staff 115 Apr 7 12:57 pyls.py
虽然这个示例看起来十分简单(事实上也确实简单),却可以给出一个在系统编程中使用Python的通用思路。我们经常需要使用Python对脚本或Unix命令进行“包装”(wrap)。实际上,如果在文件中一行接一行地写下命令,然后运行该文件,就可以说你已经开始在写一些基本的脚本了。接下来让我们看一个简单示例。编写例1-2所示的代码,或是直接将以下代码进行剪切和粘贴,然后运行脚本文件pysysinfo.py和bashsysinfo.sh。这些脚本文件都可以在本章的源代码中找到。例1-2和1-3如下所示:
例1-2:显示系统信息脚本 —— Python#!/usr/bin/env python
#A System Information Gathering Script
import subprocess
#Command 1
uname="uname"
uname_arg="-a"
print "Gathering system information with %s command:\n" % uname
subprocess.call([uname, uname_arg])
#Command 2
diskspace="df"
diskspace_arg="-h"
print "Gathering diskspace information %s
command:\n" % diskspace
subprocess.call([diskspace, diskspace_arg])
例1-3:
显示系统信息脚本 —— Bash#!/usr/bin/env bash
#A System Information Gathering Script
#Command 1
UNAME="uname -a"
printf "Gathering system information with the
$UNAME command: \n\n"
$UNAME
#Command 2
DISKSPACE="df -h"
printf "Gathering diskspace information with
the $DISKSPACE command: \n\n"
$DISKSPACE
如果把这两个脚本都读一遍,会发现它们看起来非常相似。如果分别运行这两个脚本,所看到的输出结果也是完全相同的。需要注意的是,在使用subprocess.call时,将命令与参数完全分开的写法并不是必需的,也可以像下面这样写:subprocess.call("df -h",shell=True)
到目前为止,我们已经学习了很多,但仍没能将import和subprocess完全解释清楚。在Python脚本程序中我们加载了subprocess模块,subprocess模块已经包含了使用Python实现系统调用的代码。
正如之前提到的,加载模块(例如加载subprocess)仅仅是将可以使用的代码文件加载进来,也可以创建自己的模块或文件,供以后重复使用,这与加载subprocess模块的方式相同。模块并没什么神奇,只不过是一个写有代码的文件罢了。IPython shell的一个非常好的优点就是可以对模块或文件进行检查,查看其内部可用的属性。对于Unix,这非常类似于在/usr/bin目录下运行ls命令。如果你恰好刚开始使用Ubuntu或是Solaris系统,而已经用惯了Red Hat系统,那么你可能会在/usr/bin下使用ls命令去查看wget、curl或是lynx命令是否可用。现在如果你想使用在/usr/bin目录下找到的某个工具,只要简单地输入命令名称即可,例如/usr/bin/wget。