《UNIX/Linux 系统管理技术手册(第四版)》——2.5 Python脚本编程

本节书摘来自异步社区《UNIX/Linux 系统管理技术手册(第四版)》一书中的第2章,第2.5节,作者:【美】Evi Nemeth , Garth Snyder , Trent R.Hein , Ben Whaley著,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.5 Python脚本编程

UNIX/Linux 系统管理技术手册(第四版)
随着项目变得越来越大、越来越复杂,面向对象的设计和实现所带来的好处,也就变得越来越清楚。Perl错过了大概5年时间,没有提供OO特性,虽然它后来又拼命去追赶,但Perl版的面向对象编程仍然显得有点儿牵强。

本节介绍Python 2。Python 3尚在开发之中,可能在本书没过时之前就能发布。但是和Perl 6不一样的是,它看上去更像是一种增量更新。

有着很强OO背景的工程师通常会喜欢Python和Ruby,这两种脚本编程语言都有一种明显的OO特质。目前,Python似乎正处于采纳曲线的下降沿,所以对于系统管理来说,它是一种相当流行的工具。包括OpenSolaris在内的几种操作系统,主要利用了Python的脚本功能。与此相对照,Ruby仍然主要用于Web开发,很少用作一般性的脚本编程。

Guido van Rossum发明了Python。与Perl相比,Python的代码更好写,也更好读。Python提供了一种易于理解的语法,即使没开发过这种代码,也很容易掌握。如果觉得要记住用哪种比较操作符很累人,那么会喜欢上Python整齐划一的方式。Python还提供更多的数据类型,有些系统管理员会发现它们很有用。

如果系统上还没装好Python,可以看看操作系统提供商或者发布方给出的软件包清单。它是一种极其常见的软件包,应该到处都有。如果没找到,可以从python.org下载Python的源代码。这个地方也一个集中位置,可以找到其他人开发的附加模块。

对于Python而言,要想获得比我们在这儿给出的介绍更全面的内容,Mark Pilgrim的Dive Into Python是一个非常好的起步点。从diveintopython.org可以(免费)阅读或者下载这份文档,也可以购买Apress出版的印刷版图书。在2.7节里可以找到完整的参考文献。

2.5.1 Python快速入门
还像往常一样,我们先从一个简单“Hello,world!”脚本开始。果不其然,Python的“Hello, world!”几乎和Perl的一模一样。

#!/usr/bin/python print "Hello,  world!"

要让这个脚本可以运行,只要设置它的可执行位,扩展直接调用python来解释这个脚本:

$ chmod +x  helloworld

$ ./helloworld

Hello, world!

这样的一行程序不能体现出Python对传统的突破,这一突破恶名在外,也就是说,缩行在逻辑上很重要。Python不用花括号、方括号,或者begin和end来界定代码块。处于同一缩进级别的语句自动构成代码块。缩行的风格(空格或者制表符,缩进的深度)则无关紧要。Python的代码分块最好用例子来展示,所以下面就用一条if-then-else语句来说明:

#!/usr/bin/python import sys

a = sys.argv[1]

if a == "1":

print 'a is  one'

print 'This is  still the then clause of  the if statement.'

else:

print 'a is',  a

print 'This is  still the else  clause of  the if statement.'
print 'This is  after the if statement.'

第三行导入sys模块,它包含数组argv。then和else子句都有两行,每一部分都缩进到相同的层次。最后的print语句在if语句之外。和在Perl里的情况一样,Python的print语句也接受任意数量的参数。但和Perl不一样的是,Python自动在每对参数之间都插入一个空格,并提供一个换行符。可以在print行的末尾多加一个逗号,消除这个换行符;参数为空则告诉print不要输出换行符。

在一行末尾的冒号一般是该行引入的一个联系符,它和随后的一个缩进块关联到一起。

$ python blockexample 1

a is  one

This is  still the then clause of  the if statement. This is  after the if statement.

$ python blockexample 2

a is  2

This  is  still the else  clause of  the if statement. This is  after the if statement.

Python的缩行惯例使得代码格式上的灵活度更低了,但它也有优点,即不同的人所编写的代码看上去都一样,而且还意味着不需要搞得代码里到处都有分号,而这些烦人的分号就只为了结束语句。

Python里的注释用一个井号(#)开头,一直持续到行尾,同bash和Perl里的用法一样。

在代码行用反斜线结尾,就可以把长长的代码行分成多行来写。这样做的时候,只有第一行代码的缩进才重要。不过,如果愿意,可以让后续的代码行都缩进。即使没有出现反斜线,但圆括号、方括号或者花括号不配对的代码行仍会自动触发续行,但如果出现这样的情况,可以在代码里包含反斜线,让代码的结构更清晰。

有些剪切和粘贴操作会把制表符(tab)转换为空格,除非知道自己要什么,否则这会让人抓狂。黄金法则是,绝对不要混用制表符和空格;缩进要么用制表符,要么用空格。许多软件采用传统的假设,让制表符应该等于8个空格的距离,对于代码的可读性来说,这确实缩进得太厉害了。大多数Python用户似乎都偏向于采用空格,而且缩进4个字符。

不管决定怎样处理缩行的问题,大多数编辑器都有若干选项,要么只用空白让制表符为非法,要么让空格和制表符显示得不一样,从而帮助用户搞得清楚。在万不得已的情况下,还可以用expand命令把制表符转为空格,或者通过perl -pe命令用一个更容易看到的字符串替换制表符。

2.5.2 对象、字符串、数、列表、字典、元组和文件
Python中所有的数据类型都是对象,比起Perl中的数据类型来说,这一点让它们更强大,也更灵活。

在Python里,列表用方括号而不是圆括号括起来。数组的索引(下标)从0开始,在本章介绍的3种脚本编程语言中,这是为数不多的几种没有变化的概念之一。

Python里新出现了一种叫做“元组(tuple)”的数据类型,它实质上是不能变的列表。元组比数组更快,对于实际上不应该被修改的数据来说,用元组表示更合适。除了用圆括号而不是方括号做定界符之外,元组的语法和列表的一样。因为(thing)看上去是一个简单的代数表达式,因此,对于只包含一个元素的元组,需要用一个额外的逗号来消除它们的含糊意思:(thing, )。

下面是Python中出现的几种基本变量和数据类型:

#!/usr/bin/python name = 'Gwen'

rating = 10

characters = [ 'SpongeBob',  'Patrick', 'Squidward' ]

elements = ( 'lithium', 'carbon', 'boron' )

print "name:\t%s\nrating:\t%d" % (name,  rating)

print "characters:\t%s" % characters print "elements:\t%s" % (elements, )

这个例子产生的输出如下:

$ python objects name: Gwen rating: 10

characters: ['SpongeBob',  'Patrick', 'Squidward']

elements: ('lithium',  'carbon', 'boron')

Python中的变量不会从语法上体现出来,也不会做类型声明,但是它们所指的对象的确有一种支持类型。在大多数情况下,Python不会替用户自动做类型转换,但是单个函数或者操作符可以做转换。例如,不显式地把数值转换为它的字符串表示形式的话,就不能把一个数和一个字符串(用操作符+)连接起来。不过,格式化操作符和语句会强制把所有东西都转为字符串形式。每个对象都有一个字符串表示。

字符串格式化操作符%很像C或者Perl语言里的sprintf函数,但它可以用在字符串出现的任何地方。它是一个双目操作符,左边是字符串,右边是要插入的数值。如果要插入一个以上的数值,那么必须用元组来表示这些值。

Python字典和Perl的哈希一样;也就是说,它是“键/值”对的一个列表。字典常量用花括号括起来,每一对“键/值”都用一个冒号分隔。

#!/usr/bin/python

ordinal = {  1 : 'first', 2 : 'second', 3 : 'third' } print "The  ordinal array contains", ordinal print "The  ordinal of  1 is", ordinal[1]

在使用上,Python的字典又非常像数组,区别在于下标(键)可以是对象而不只是整数。

$ python dictionary

The ordinal array contains {1: 'first', 2: 'second', 3: 'third'} The  ordinal of  1 is  first

Python用对象所关联的方法把打开的文件按对象来处理。顾名思义,readline方法读取一行,所以下面的例子从/etc/passwd文件读取并打印两行内容。

#!/usr/bin/python

f = open('/etc/passwd',  'r')

print f.readline(), print f.readline(), f.close()

$ python fileio

at:x:25:25:Batch jobs  daemon:/var/spool/atjobs:/bin/true bin:x:1:1:bin:/bin:/bin/true

print语句里最后的逗号消除了换行符,因为每行在从原来的文件读入的时候就已经带一个换行符了。

2.5.3 确认输入的例子
下面的脚本片段是Python版的确认输入的程序,我们现在已经很熟悉这个例子了。它展示了子例程和命令行参数的用法,还体现了其他两种Python化的特性。

#!/usr/bin/python import sys

import os

def  show_usage(message, code = 1):

print message

print "%s:  source_dir dest_dir"  % sys.argv[0]

sys.exit(code)

if len(sys.argv) != 3:

show_usage("2 arguments  required; you  supplied %d"  % (len(sys.argv) - 1))

elif  not os.path.isdir(sys.argv[1]):

show_usage("Invalid source directory")

elif  not os.path.isdir(sys.argv[2]):

show_usage("Invalid destination  directory")

source, dest = sys.argv[1:3]

print "Source Directory is", source print "Destination Directory is", dest

除了导入sys模块之外,我们还导入了os模块,从而可以使用os.path.isdir这个例程。注意,对于模块定义的任何代号来说,import命令不会提供访问它们的捷径;必须使用从模块名开始的全名。

例程show_usage的定义里给退出码赋予了一个默认值,万一调用程序没有显式地指定这个参数,就用这个默认值退出。既然所有的数据类型都是对象,所以用引用来给函数传参。

数组sys.argv在第0个位置保存有该脚本的名字,所以它的长度比实际提供的命令行参数个数正好多1。sys.argv[1:3]这样的形式表示一个数组段。有意思的是,数组段不包括指定范围里最后的那个元素,所以这个数组段只有sys.argv[1]和sys.argv[2]两个元素。可以简单地用sys.argv[1:]把从第二个开始的所有元素都包括进来。

同bash和Perl一样,Python也有专门的一种“else if”条件;其关键字是elif。Python也没有case或者switch语句。

给soure和dest变量的平行赋值与Perl有点儿不一样,因为这两个变量本身不在一个列表里。两种形式的平行赋值在Python里都可以。

Python给数值和字符串的比较运算符都一样。“不相等”的比较运算符是!=,但却没有!这样的单目运算符;这样的单目运算符是not。也要搞清楚布尔运算符and和or。

2.5.4 循环
下面的代码片段用一个for…in结构从1循环到10。

for counter  in range(1, 10):

print counter,

和前面例子里的数组段一样,这个范围的右端点实际上没有包括进来。输出值只有1到9。

1 2 3 4 5 6 7 8 9

这是Python里唯一的for循环类型,但它功能很强大。Python的for语句有几项特性,有别于其他语言。

数值范围没有什么特殊之处。任何对象都可以支持Python的循环模型,而且最常见的对象都支持。可以通过一个字符串(按逐个字符)、一个列表、一个文件(按逐个字符、逐行或者逐块),以及一个数组段等。

循环可以产生多个值,循环变量也可以有多个。在每次循环的开头进行的赋值,就和Python正常的多重赋值一样。

for和while循环都可以在末尾加上else子句。只有当循环正常终止之后,才执行这个else子句,这和通过一条break语句退出正好相反。这一功能乍看起来似乎与直觉相反,但它能很好地处理某些用例。

下面的脚本示例接受命令行上的一个正则表达式,把它同一个列表进行匹配,列表里是白雪公主中七个小矮人的名字及其衣服的颜色。该脚本打印第一个匹配的结果,而且匹配正则表达式的部分两边用下划线区分出来。

#!/usr/bin/python import sys

import re

suits = {  'Bashful':'red', 'Sneezy':'green', 'Doc':'blue', 'Dopey':'orange',

'Grumpy':'yellow', 'Happy':'taupe',  'Sleepy':'puce' }

pattern = re.compile("(%s)" % sys.argv[1])

for  dwarf, color in  suits.items():

if pattern.search(dwarf)  or  pattern.search(color):

print "%s's  dwarf suit is  %s." % \

(pattern.sub(r"_\1_",  dwarf), pattern.sub(r"_\1_", color))

break

else:

print "No  dwarves or  dwarf suits matched the pattern."

下面是一些输出的例子:

$ python  dwarfsearch  '[aeiou]{2}'

Sn_ee_zy's dwarf suit is  gr_ee_n.

$ python dwarfsearch go

No  dwarves or  dwarf suits matched the pattern.

给suits赋值的语句,展示了Python用于字典常量的编码方式。suits.items()方法是“键/值”对的迭代器——每次循环都提取一个小矮人的名字和一种衣服颜色。如果只想通过键做循环,只需要把代码写为for dwarf in suits。

Python通过它的re模块实现对正则表达式的处理。Python语言本身没有任何有关正则表达式的功能,所以用Python处理正则表达式比用Perl要稍微麻烦一点儿。在本例中,正则表达式的pattern一开始由compile方法,用圆括号括起来第一个命令行参数进行编译,形成了一个捕获组。接着,用正则表达式对象的search和sub方法测试和修改字符串。还可以像函数那样直接调用re.search等方法,把正则表达式当做第一个参数来用。替换字符串里的1是反过去引用第一个捕获组的内容。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值