我已经创建了下面为我工作的代码,但我觉得可能有一种更好的方法来用新的Pythonic方式或更好的Python语法方式来完成这一任务。
bondCheck.py
#!/usr/bin/python
# Port bonding checker.
# cat /proc/net/bonding/bond0
import sys
import re
def usage():
print '''USAGE: %s [options] [bond_interface]
Options:
--help, -h This usage document
Arguments:
bond_interface The bonding interface to query, eg. 'bond0'. Default is 'bond0'.
''' % (sys.argv[0])
sys.exit(1)
# Parse arguments
try:
iface = sys.argv[1]
if iface in ('--help', '-h'):
usage()
except IndexError:
iface = 'bond0'
# Grab the inf0z from /proc
try:
bond = open('/proc/net/bonding/%s' % iface).read()
except IOError:
print "ERROR: Invalid interface %s\n" % iface
usage()
# Parse and output
active = 'NONE'
Link = 'NONE'
slaves = ''
state = 'OK'
links = ''
bond_status = ''
for line in bond.splitlines():
m = re.match('^Currently Active Slave: (.*)', line)
if m:
active = m.groups()[0]
m = re.match('^Slave Interface: (.*)', line)
if m:
s = m.groups()[0]
slaves += ', %s' % s
m = re.match('^Link Failure Count: (.*)', line)
if m:
l = m.groups()[0]
links += ', %s' % l
m = re.match('^MII Status: (.*)', line)
if m:
s = m.groups()[0]
if slaves == '':
bond_status = s
else:
slaves += ' %s' % s
if s != 'up':
state = 'FAULT'
print "%s: %s (%s), Active Slave: %s, PriSlave: %s (%s), SecSlave: %s (%s), LinkFailCountOnPriInt: %s, LinkFailCountOnSecInt: %s" % (iface, state, bond_status, active, slaves.split(',')[1].split()[0], slaves.split(',')[1].split()[1], slaves.split(',')[2].split()[0], slaves.split(',')[2].split()[1], links.split(',')[1], links.split(',')[2])$ ./bondCheck.py
bond0: OK (up), Active Slave: ens3f0, PriSlave: ens3f0 (up), SecSlave: ens3f1 (up), LinkFailCountOnPriInt: 0, LinkFailCountOnSecInt: 0编辑:
cat /proc/net/bonding/bond0
Bonding Mode: fault-tolerance (active-backup)
Primary Slave: ens3f0 (primary_reselect always)
Currently Active Slave: ens3f0
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 2500
Down Delay (ms): 300
Slave Interface: ens3f0
MII Status: up
Speed: 20000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 5a:19:bb:00:00:48
Slave queue ID: 0
Slave Interface: ens3f1
MII Status: up
Speed: 20000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 5a:19:bb:00:00:49
Slave queue ID: 0发布于 2020-03-13 17:07:06
作为一项规则,我不喜欢触发异常,甚至是受控异常。原因之一是它们的处理成本更高,而且顾名思义,它们应该保持为例外。
因此,与其这样做,不如:
try:
bond = open('/proc/net/bonding/%s' % iface).read()
except IOError:
print "ERROR: Invalid interface %s\n" % iface
usage()我会有这样的东西:
import sys, os
iface = 'bond0'
bond = ('/proc/net/bonding/%s' % iface)
if not os.path.exists(bond):
print "ERROR: Invalid interface %s\n" % iface
sys.exit(1)
# continue注意:看到您正在使用Python2.x,我尝试提供兼容的代码。
与其盲目地尝试读取可能一开始就不存在的文件,我只是使用os.path来确定它的存在(也可以使用isfile函数)。
我还返回了一个退出代码,如果您要从另一个bash脚本调用这个脚本,那么您可能想知道输出是否与预期的一样,或者是否存在可能的错误,比如网络链接中断。不只是返回0(成功)或1(失败),您可以根据遇到的错误类型来调整值。那么将特殊码放在心上是很有用的。
我看到您已经在代码中使用了sys.exit(1),这是很好的,但是在usage函数中,它是最不有用的。考虑返回代码的其他部分中的退出代码,包括异常。一种方法是有一个带有try catch的主finally块,以便总是返回退出代码,默认情况下这可能是0。
不过,您仍然可以在这个块中进行异常处理,因为您可能会遇到一些权限问题,这取决于用户和操作系统。只是我会避免在容易预料和测试的情况下出现异常。
考虑记录异常,甚至考虑控制台输出或调试信息。最近关于这个主题的讨论:自定义异常处理函数还是日志库?
这对于无人值守的脚本尤其重要。在这种情况下,如果脚本总是以交互方式运行,那么它可能就不那么重要了。但是,当您在一些很小的SSH或屏幕终端会话中使用一个小缓冲区大小和难以滚动的文本时,在文件中有一个跟踪是很好的。
对于/proc/net/bonding/或bond0这样的半常量变量,我尝试在脚本的基础上将它们重新组合在一起。路径和接口名称可能因操作系统而异,当基本变量名称不分散在整个平台上时,将代码移植到另一个平台会更容易。显然,它们应该只定义一次,绝对避免重复。我为至少运行在3种不同版本Linux上的服务器开发脚本,有时我会感到意外.
关于代码本身:执行print的最后一行很难读懂。所有的分裂都是不必要的,甚至是不安全的。如果/proc/net/bonding/bond0的输出发生变化,或者从服务器的数量少于2,您的代码可能会失败。
理想情况下,您应该有准备使用的变量,并只需打印它们。所有的处理、解析、验证等都必须在此之前进行。
让我们以这个片段为例:
m = re.match('^Slave Interface: (.*)', line)
if m:
s = m.groups()[0]
slaves += ', %s' % s您的代码迭代两次。在第一次迭代时,slaves的值是:, ens3f0。在第二次迭代中,它是:, ens3f0 up, ens3f1。注意前面的逗号。您似乎还不熟悉Python结构,如列表或字典,因此您需要使用多余的字符串操作技术。在这里,我将如何做,使用一个简单的列表:
首先在代码中添加以下内容,例如在for循环之前:
slave_interfaces = []我们只需定义一个空列表。然后,您的代码变成:
m = re.match('^Slave Interface: (.*)', line)
if m:
slave_interfaces.append(m.group(1).strip()) 如果找到匹配,则将该值追加到列表中,这意味着添加一个元素。注意添加了strip()来修剪可能围绕接口名称的空白。
正则表达式不仅可以匹配,还可以捕获。因为m.group(1)已经包含了接口的名称,所以可以使用它。现在,在第一次迭代时,slave_interfaces的值是:['ens3f0']。在第二次迭代中,它是:['ens3f0', 'ens3f1']。您有一个包含两个元素的列表,并且可以按索引号对每个元素进行寻址,例如slave_interfaces[0] = 'ens3f0'和slave_interfaces[1] = 'ens3f1'。您可以检查元素的数量:len(slave_interfaces)将返回2。因此您预先知道,使用大于1的索引将导致错误(IndexError:列表索引超出范围)。
生成逗号分隔的列表就像加入一样容易:
','.join(slave_interfaces)=> 'ens3f0,ens3f1'
最后,对于解析参数(如果您有Python2.7),库解析解析库提供了更多的灵活性。还请看一下add_help函数。当您使用可能没有特定顺序的多个参数开发更复杂的脚本时,您的方法将无法很好地扩展。
https://codereview.stackexchange.com/questions/238786
复制相似问题