在本文中,我们将会探索使用Python编程语言工具来检索Linux系统各种信息。走你。
探索platform模块
platform模块在标准库中,它有很多运行我们获得众多系统信息的函数。让我们运行Python解释器来探索它们中的一些函数,那就从platform.uname()函数开始吧:
1
2
3
|
>>>
import
platform
>>> platform.uname()
(
'Linux'
,
'fedora.echorand'
,
'3.7.4-204.fc18.x86_64'
,
'#1 SMP Wed Jan 23 16:44:29 UTC 2013'
,
'x86_64'
)
|
如果你已知道linux上的uname命令,那么你就会认出来这个函数就是这个命令的一个接口。在Python 2上,它会返回一个包含系统类型(或者内核版本),主机名,版本,发布版本,机器的硬件以及处理器信息元组(tuple)。你可以使用下标访问个别属性,像这样:
1
2
|
>>> platform.uname()[
0
]
'Linux'
|
在Python 3上,这个函数返回的是一个命名元组:
1
2
3
4
5
|
>>> platform.uname()
uname_result(system
=
'Linux'
, node
=
'fedora.echorand'
,
release
=
'3.7.4-204.fc18.x86_64'
, version
=
'
#1 SMP Wed Jan 23 16:44:29
UTC
2013
', machine='
x86_64
', processor='
x86_64')
|
因为返回结果是一个命名元组,这就可以简单地通过名字来指定特定的属性,而不是必须记住下标,像这样:
1
2
|
>>> platform.uname().system
'Linux'
|
platform模块还有一些上面属性的直接接口,像这样:
1
2
3
4
5
|
>>> platform.system()
'Linux'
>>> platform.release()
'3.7.4-204.fc18.x86_64'
|
linux_distribution()函数返回的有关你所在的linux发布版本的详细信息。例如,在Fedora 18系统上,这个命令会返回如下信息:
1
2
|
>>> platform.linux_distribution()
(
'Fedora'
,
'18'
,
'Spherical Cow'
)
|
这个返回结果中包含了版本发布名,版本以及代号元组。特定的Python版本支持的发布版本上可以通过_supported_dists显示的值获得。
1
2
3
4
|
>>> platform._supported_dists
(
'SuSE'
,
'debian'
,
'fedora'
,
'redhat'
,
'centos'
,
'mandrake'
,
'mandriva'
,
'rocks'
,
'slackware'
,
'yellowdog'
,
'gentoo'
,
'UnitedLinux'
,
'turbolinux'
)
|
如果你的linux发布版本不在其中(或者其中之一的衍生发行版)。那么你很可能调用了上面这个函数而看不到任何有用的信息。
platform模块的最后一个函数,我们将会看看architecture()函数。当你无参的调用这个函数,它会返回包含架构位数以及python可执行的格式的元组,像这样:
1
2
|
>>> platform.architecture()
(
'64bit'
,
'ELF'
)
|
在32位的系统上,你将会看到:
1
2
|
>>> platform.architecture()
(
'32bit'
,
'ELF'
)
|
如果你指定了系统上其他任何可执行的,你都将会获得相似的结果,如同这样:
1
2
|
>>> platform.architecture(executable
=
'/usr/bin/ls'
)
(
'64bit'
,
'ELF'
)
|
鼓励探索platform模块的除了这些的其它函数,找出你现在运行的Python版本。如果你想知道这个模块是如何获取这些信息的,你可以深入查看PYthon源码目录下的Lib/platform.py文件。
os和sys模块也可以获得一些系统属性,例如原生的字节序。接下来,我们超越Python标准库模块,去探索一些在linux系统通过proc和sysfs文件系统使之访问信息成为可能。注意的是通过文件系统来访问信息将会在不同的硬件架构有所不同。所以在读本文或是写脚本时要时刻记住可以试图从这些文件获取信息。
CPU信息
/proc/cpuinfo文件包含了你的系统处理器单元的信息。例如,这里就是python版的linux命令cat /proc/cpuinfo所做的事:
1
2
3
4
5
6
7
8
9
10
|
#! /usr/bin/env python
""" print out the /proc/cpuinfo
file
"""
from
__future__
import
print_function
with
open
(
'/proc/cpuinfo'
) as f:
for
line
in
f:
print
(line.rstrip(
'\n'
))
|
当你使用Python 2 或者 Python 3执行这个程序时,你会在屏幕上看到所有/proc/cpuinfo的内容(在上面的程序里,rstrip()方法用来删除每行末尾的换行符)
在下面的代码里列举了使用startwith()字符串方法来显示你的处理器单元的模式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#! /usr/bin/env python
""" Print the model of your
processing units
"""
from
__future__
import
print_function
with
open
(
'/proc/cpuinfo'
) as f:
for
line
in
f:
# Ignore the blank line separating the information between
# details about two processing units
if
line.strip():
if
line.rstrip(
'\n'
).startswith(
'model name'
):
model_name
=
line.rstrip(
'\n'
).split(
':'
)[
1
]
print
(model_name)
|
当你运行这个程序后,你应该会看到你的每个处理器单元的模式名。例如,这里就是在我电脑上所看到的。
1
2
3
4
|
Intel(R) Core(TM) i7-3520M CPU @
2
.90GHz
Intel(R) Core(TM) i7-3520M CPU @
2
.90GHz
Intel(R) Core(TM) i7-3520M CPU @
2
.90GHz
Intel(R) Core(TM) i7-3520M CPU @
2
.90GHz
|
迄今为止,我们已有两种方式来找出我们所使用的系统的架构。从技术上讲是正确的,两个方 式实际上报告了你系统运行的内核架构,所以,如果你的电脑是64位的,但是运行的是32位的内核,然后上面的方法还是将会显示为32位的架构。你可以通过从/proc/cpuinfo所列举的标志中查找lm标志,来找到你的电 脑的真实的架构。lm标志代表了长模式,只有64位架构的才会显示它。下面的程序将会指导你怎样做:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#! /usr/bin/env python
""" Find the real bit architecture
"""
from
__future__
import
print_function
with
open
(
'/proc/cpuinfo'
) as f:
for
line
in
f:
# Ignore the blank line separating the information between
# details about two processing units
if
line.strip():
if
line.rstrip(
'\n'
).startswith(
'flags'
) \
or
line.rstrip(
'\n'
).startswith(
'Features'
):
if
'lm'
in
line.rstrip(
'\n'
).split():
print
(
'64-bit'
)
else
:
print
(
'32-bit'
)
|
如我们所看到那样,读取/proc/cpuinfo文件以及使用简单文本处理技术就可以获得我们要查找的数据是可能的。为了给其他程序更好的使用这些数据,一个更好的主意就是使/proc/cpuinfo的内容成为标准的数据结构,譬如字典(dictionary)。这个注意很简单:如果你查看这个文件的内容,你就会发现对于每个处理器单元,都有好些键值对(在先前的例子中,我们打印了每个处理器的模型名,即模型名就是关键字)。不同的处理器单元的信息可以使用空白行隔开。构造一个字典数据结构包含每个处理器单元的关键字是很简单的。对于每个关键字,对于处理器单元的值都在/proc/cpuinfo文件中。下面的代码将会指导你怎么做。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
#!/usr/bin/env/ python
"""
/proc/cpuinfo as a Python dict
"""
from
__future__
import
print_function
from
collections
import
OrderedDict
import
pprint
def
cpuinfo():
''' Return the information in /proc/cpuinfo
as a dictionary in the following format:
cpu_info['proc0']={...}
cpu_info['proc1']={...}
'''
cpuinfo
=
OrderedDict()
procinfo
=
OrderedDict()
nprocs
=
0
with
open
(
'/proc/cpuinfo'
) as f:
for
line
in
f:
if
not
line.strip():
# end of one processor
cpuinfo[
'proc%s'
%
nprocs]
=
procinfo
nprocs
=
nprocs
+
1
# Reset
procinfo
=
OrderedDict()
else
:
if
len
(line.split(
':'
))
=
=
2
:
procinfo[line.split(
':'
)[
0
].strip()]
=
line.split(
':'
)[
1
].strip()
else
:
procinfo[line.split(
':'
)[
0
].strip()]
=
''
return
cpuinfo
if
__name__
=
=
'__main__'
:
cpuinfo
=
cpuinfo()
for
processor
in
cpuinfo.keys():
print
(cpuinfo[processor][
'model name'
])
|
这段代码中使用了OrderedDict(有序字典)而不是常规的字典,能够使用键值有序的存储在文件里。所以,第一个处理器单元的数据之后就是第二个处理器单元的数据,以此类推。你可以使用过滤器来过滤你所查找的信息(如同在if __name__ == ‘__main__’块中演示的那样)。上面的程序每次执行后都会打印每个处理器单元的模型名(如通过cpuinfo[processor]['model name']语句表明的那样)
1
2
3
4
|
Intel(R) Core(TM) i7-3520M CPU @
2
.90GHz
Intel(R) Core(TM) i7-3520M CPU @
2
.90GHz
Intel(R) Core(TM) i7-3520M CPU @
2
.90GHz
Intel(R) Core(TM) i7-3520M CPU @
2
.90GHz
|
内存信息
和/proc/cpuinfo相似,文件/proc/meminfo包含了你电脑的主存的信息。下面的这个程序创建了一个使用这个文件的内容填充的字典。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#!/usr/bin/env python
from
__future__
import
print_function
from
collections
import
OrderedDict
def
meminfo():
''' Return the information in /proc/meminfo
as a dictionary '''
meminfo
=
OrderedDict()
with
open
(
'/proc/meminfo'
) as f:
for
line
in
f:
meminfo[line.split(
':'
)[
0
]]
=
line.split(
':'
)[
1
].strip()
return
meminfo
if
__name__
=
=
'__main__'
:
#print(meminfo())
meminfo
=
meminfo()
print
(
'Total memory: {0}'
.
format
(meminfo[
'MemTotal'
]))
print
(
'Free memory: {0}'
.
format
(meminfo[
'MemFree'
]))
|
像先前的,通过它的关键字,你可以访问任何你查询的指定信息(在if __name__==__main__块中有所表示)。当你执行这个程序,你该会看到像下面类似的输出:
1
2
|
Total memory:
7897012
kB
Free memory:
249508
kB
|
网络统计信息
接下来,我们会探索我们电脑系统的网络设备。我们将会获得系统的网络接口,以及当系统重启之后通过它们数据发送和接受数据的信息。 /proc/net/dev文件让这些信息可用。如果你检查了这个文件的内容,你就会注意到头一两行包含了头信息等等,这个文件第一列是网络接口名,第二和第三列显示了接收和发送的字节数信息(例如总发送字节数,包数,错误等等)。这里我们所感兴趣的就是他哦难过不同的网络设备提取出总发送数据和接收数据。下面的代码展示了怎么从/proc/net/dev文件中提取出这些信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#!/usr/bin/env python
from
__future__
import
print_function
from
collections
import
namedtuple
def
netdevs():
''' RX and TX bytes for each of the network devices '''
with
open
(
'/proc/net/dev'
) as f:
net_dump
=
f.readlines()
device_data
=
{}
data
=
namedtuple(
'data'
,[
'rx'
,
'tx'
])
for
line
in
net_dump[
2
:]:
line
=
line.split(
':'
)
if
line[
0
].strip() !
=
'lo'
:
device_data[line[
0
].strip()]
=
data(
float
(line[
1
].split()[
0
])
/
(
1024.0
*
1024.0
),
float
(line[
1
].split()[
8
])
/
(
1024.0
*
1024.0
))
return
device_data
if
__name__
=
=
'__main__'
:
netdevs
=
netdevs()
for
dev
in
netdevs.keys():
print
(
'{0}: {1} MiB {2} MiB'
.
format
(dev, netdevs[dev].rx, netdevs[dev].tx))<span style
=
"font-family:'sans serif', tahoma, verdana, helvetica;font-size:10pt;line-height:1.5;"
> <
/
span>
|
当你运行上面的程序,下面这个输出就会显示从你最近重启之后网络设备总接收和发送的数据,单位为兆。
1
2
|
em1:
0.0
MiB
0.0
MiB
wlan0:
2651.40951061
MiB
183.173976898
MiB
|
你可以使用持久的数据存储机制来连接,来写出自己的数据使用监控程序。
进程信息
/proc目录包含了所有正运行的进程目录。这些目录的名字和进程的标识符是一样的。所以,如果你遍历/proc目录下那些使用数字作为它们的名字的目录,你就会获得所有现在正在运行的进程列表。在下面的代码中process_list()函数返回所有现在正在运行的进程的标识符列表。当你执行这个程序后,这个列表的长度就是在系统上运行的总进程数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#!/usr/bin/env python
"""
List of all process IDs currently active
"""
from
__future__
import
print_function
import
os
def
process_list():
pids
=
[]
for
subdir
in
os.listdir(
'/proc'
):
if
subdir.isdigit():
pids.append(subdir)
return
pids
if
__name__
=
=
'__main__'
:
pids
=
process_list()
print
(
'Total number of running processes:: {0}'
.
format
(
len
(pids)))
|
上面的程序当执行后会显示和下面类似的输出:
1
|
Total number of running processes::
229
|
每个进程目录包含了一些其他文件和目录,如进程命令的调用,它正使用的共享库以及其它的。
块设备
下一个程序通过读sysfs虚拟文件系统列出所有块设备。你系统中的块设备可以从/sys/block目录中找到。因此可能会有/sys/block/sda、/sys/block/sdb等这样的目录。为了获取所有这些设备,我们使用正则表达式对/sys/block目录进行扫描提取感兴趣的块设备。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#!/usr/bin/env python
"""
Read block device data from sysfs
"""
from
__future__
import
print_function
import
glob
import
re
import
os
# Add any other device pattern to read from
dev_pattern
=
[
'sd.*'
,
'mmcblk*'
]
def
size(device):
nr_sectors
=
open
(device
+
'/size'
).read().rstrip(
'\n'
)
sect_size
=
open
(device
+
'/queue/hw_sector_size'
).read().rstrip(
'\n'
)
# The sect_size is in bytes, so we convert it to GiB and then send it back
return
(
float
(nr_sectors)
*
float
(sect_size))
/
(
1024.0
*
1024.0
*
1024.0
)
def
detect_devs():
for
device
in
glob.glob(
'/sys/block/*'
):
for
pattern
in
dev_pattern:
if
re.
compile
(pattern).match(os.path.basename(device)):
print
(
'Device:: {0}, Size:: {1} GiB'
.
format
(device, size(device)))
if
__name__
=
=
'__main__'
:
detect_devs()
|
如果你运行该程序,你将会看到下述类似的输出:
1
2
|
Device:: /sys/block/sda, Size::
465.761741638
GiB
Device:: /sys/block/mmcblk0, Size::
3.70703125
GiB
|
当我运行该程序的时候,有个SD内存卡插在电脑上,因此你会看到程序检测到了它。你也可以扩展该程序识别其它块设备(比如虚拟硬盘)。