虽然脚本周一的时候就写好了,但是昨天才是第一次正式使用。加上昨天写了第二篇shell的tips,所以expect+python的脚本gen_report今天才写。

首先说一下背景。由于工作需要,有时我需要ssh到服务器上拉取运行数据生成报表。整个过程很枯燥,就是登录服务器,输入密码,运行二三十条很像的命令,把数据复制到microsoft excel或者libre office calc中计算。一言以蔽之:整个人肉操作。

很明显,如果让我天天干,我肯定不愿意。但是即使不是天天干,一周干一次,我也不愿意,因为命令执行很慢,来回弄肯定要半天。按照《时间管理 给系统管理员》,这种时候最适合写脚本了。

常规策略是在服务器上写好一个脚本,ssh上去执行一下,再使用scp把结果下载下来,最后使用比如python来解析生成csv等报表。但是,不行。首先遇到的问题就是服务器貌似不支持publickey,其次服务器上命令有限制(很常见,你不是管理员),不支持publickey的直接后果是ssh后执行命令和scp无法使用,只能另外寻找方法。

由于某些原因,我知道expect。虽然交互式的命令很好,但是如果你要让交互式的命令自动化的话,却很麻烦,比如ssh,ftp。这个时候expect可以帮助你解决问题。证明是网上搜索expect ssh login一抓一大把。所以我现在的考虑是通过expect代替ssh登录服务器执行命令。因为不能用scp,所以考虑把expect通过重定向或者tee放入某个文件中,最后让python解析这个日志文件即可。(最近重新看了点expect的书,貌似expect可以直接设置日志文件,不用tee之类的重定向,之后有空可以尝试下。)

基本策略确定了,方向基本也清楚了。由于涉及expect和python两种语言和程序,所以我选择shell做总控制的脚本。以下是总控制脚本即gen_report的内容(部分和工作相关的内容已经做了修改):

Shell

#!/bin/sh

FETCH_LOG=./fetch_log

PARSE_LOG=./parse_log

TODAY=`date +%Y-%m-%d`

LOG_FILE=foo-$TODAY.log

CSV_FILE=foo-$TODAY.csv

# $1 is password

$FETCH_LOG $1 2>&1 | tee $LOG_FILE

$PARSE_LOG $LOG_FILE | tee $CSV_FILE

rm $LOG_FILE

1

2

3

4

5

6

7

8

9

10

11

12

#!/bin/sh

FETCH_LOG=./fetch_log

PARSE_LOG=./parse_log

TODAY=`date+%Y-%m-%d`

LOG_FILE=foo-$TODAY.log

CSV_FILE=foo-$TODAY.csv

# $1 is password

$FETCH_LOG$12>&1|tee$LOG_FILE

$PARSE_LOG$LOG_FILE|tee$CSV_FILE

rm$LOG_FILE

解释一下,fetch_log是expect脚本,parse_log是python脚本,中间文件是LOG_FILE,最后生成的是CSV_FILE。

脚本需要输入的是$1,即注释中的密码。考虑到有人不知道tee这个命令,解释一下tee是一个把内容输出到文件和标准输出的命令。其次2>&1含义是把错误输出到标准输出中,否则你的日志文件中可能看不到错误信息。

脚本逻辑很简单,如果之前的解释看懂了的话,三行脚本的内容很容易理解。就是expect获取输出,python解析,最后删除中间文件。

fetch_log即expect脚本由于和工作相关的内容比较多,这里只列出部分:

#!/usr/bin/expect -f

set timeout -1

set prompt "*$ "

proc stat {a b c d} {

// omit

}

set password [lindex $argv 0]

spawn ssh user@server

expect "*Password:*" {

send "$password\n"

}

stat "1" "2" "3" "4"

stat "2" "2" "3" "4"

stat "3" "2" "3" "4"

stat "4" "2" "3" "4"

expect $prompt {

exit

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

#!/usr/bin/expect -f

settimeout-1

setprompt"*$ "

procstat{abcd}{

// omit

}

setpassword[lindex$argv0]

spawnsshuser@server

expect"*Password:*"{

send"$password\n"

}

stat"1""2""3""4"

stat"2""2""3""4"

stat"3""2""3""4"

stat"4""2""3""4"

expect$prompt{

exit

}

解释一下,spawn->expect password->enter password是典型的登录服务器的方式。之后的stat是我需要在远程服务器上执行的命令,最后执行完之后exit。需要注意的是expect默认超时是10s,由于服务器命令执行比较耗时,所以我调整为-1。更多的expect资料建议man expect,google expect或者看《exploring expect》。

最后是解析的python脚本parse_log。这个脚本预期的输入格式是这样的:

$prompt $key

command

$result

1

2

3

$prompt$key

command

$result

第一行为提示符+命令关键字,第二行为具体命令,第三行为执行结果(单行)。python解析脚本如下:

Python

#!/usr/bin/env python

import sys

def row(key, count):

return key.split(',') + [count]

def parse(filepath):

f = open(filepath)

rows = []

while True:

line = f.readline()

if not line:

break

if line.startswith('prompt:'):

# pass command

f.readline()

count = f.readline()

# cut prompt from position 6

rows.append(row(line.rstrip()[6:], count.rstrip()))

f.close()

return rows

if __name__ == "__main__":

print 'header'

for row in parse(sys.argv[1]):

print ','.join(row)

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

#!/usr/bin/env python

importsys

defrow(key,count):

returnkey.split(',')+[count]

defparse(filepath):

f=open(filepath)

rows=[]

whileTrue:

line=f.readline()

ifnotline:

break

ifline.startswith('prompt:'):

# pass command

f.readline()

count=f.readline()

# cut prompt from position 6

rows.append(row(line.rstrip()[6:],count.rstrip()))

f.close()

returnrows

if__name__=="__main__":

print'header'

forrowinparse(sys.argv[1]):

print','.join(row)

至此,所有脚本介绍完毕。昨天执行的时候运行良好,大概只花了半个多小时,不用自己去关注。结果大致是个csv的表格,这里就不具体列出来了。

最后,感叹了linux果然是开发工程师必学的工具啊,对平时的任务非常有用,相比之下,我还真不知道windows该怎么弄……

python生成报表并打印_使用expect+python拉取数据并生成报表相关推荐

  1. 分享:Python使用cookielib和urllib2模拟登陆新浪微博并抓取数据

    Python使用cookielib和urllib2模拟登陆新浪微博并抓取数据 http://my.oschina.net/leopardsaga/blog/94774

  2. python 在同一行打印_关于打印:Python:在同一行上打印多个

    我想运行一个脚本,它基本上显示如下内容: Installing XXX...               [DONE] 现在,我使用print在函数成功后打印整行.但是,现在我希望它首先打印" ...

  3. python打印数字倒三角形_在python中用while语句打印出倒三角形【python 三角形】

    在python中用while语句打印出倒三角形 i = int(input("shuru")) a = 0 while a b = 0 while b print(end=&quo ...

  4. list python 访问 键值对_学完Python,我决定熬夜整理这篇总结...

    作者:Caso_卡索 来源:http://suo.im/5wzRqt 一.了解Python 1.Python之父 Guido Van Rossum,一位荷兰程序员,在1989年圣诞节编写了Pyhon语 ...

  5. python将字符串逆序_为什么说Python是一门伟大的入门语言?(附免费教程)

    Python 是一门伟大的入门语言.作为一门伟大的编程语言,一定要具备一些特征,其中有五项特征是非常重要的: 非常棒的首次体验:就像书的开始,首先一定要能够"沉迷",学习新知识一定 ...

  6. python数据挖掘要学多久_怎么自学python,大概要多久?

    你需要100天,不以项目为学习目标的都是耍流氓.我曾经长期挣扎在python学习的路上,一直不得其解.我乎推荐得很多课我都看过.能坚持下来给大神跪了,我自学一年竟然还在新手区.我一度想放弃,我是不是不 ...

  7. python wx窗口无法关闭_菜鸟学Python,双手奉上老司机给上路新手总结的Python实战问题…...

    针对Python这一话题每天后台都会有不少小伙伴提出问题,下面我就将这些问题进行汇整,产出"Python实战问题篇",我认为这些问题非常具有代表性,希望可以帮到大家. 第一类问题: ...

  8. python write 写多行_如何用 Python 执行单行命令

    一般来说,面对日常处理的一些小任务,直接用 sed,grep 之类的就可以搞定,更复杂一点的就会考虑 awk 或者用一些现成的轮子,要是 awk 搞不定我就只好用 Python 了.但有些时候,我仅仅 ...

  9. python中的列表理解_掌握『Python列表理解』需要知道的9件事,你知道了吗?

    越来越多的人开始学习Python,它已经成为最流行的编程语言之一,这几乎发生在所有领域.比如网络开发.科学计算,当然还有人工智能. 无论想用python干什么,都绕不开学习Python的数据结构.变量 ...

最新文章

  1. 部署可扩展的目标检测管道:推理过程(上)
  2. 【C++ 语言】命名空间 ( namespace | 命名空间定义 | 命名空间嵌套 | 域作用符 | 与 include 对比 )
  3. php汽车配件管理系统,汽配仓库管理系统_汽配库存管理系统
  4. 重新设计Videoland的登录页面— UX案例研究
  5. 三维视觉基础之世界坐标系、相机坐标系、图像坐标系和像素坐标系之间的转换关系
  6. Java面试通关要点汇总整理
  7. 机器学习单词记录--02章单变量相性回归
  8. C# WPF网络实时监测客户端
  9. 6C.项链(C++)
  10. 五阶魔方公式java_五阶魔方花样有多漂亮,关键是有点难
  11. 14岁初中生将免去四考,保送清华本硕博连读,乡亲们敲锣打鼓祝贺
  12. Android Studio 星座查询系统
  13. 计算机鼠标不动了,计算机鼠标不动了怎么解决?
  14. ARM中ABORT(中止)的理解
  15. 无线路由器设置成无线AP,解决家里设备不在一个网段的尴尬
  16. TortoiseGit 假定未变更
  17. 怎么在IOS上阅读txt小说,小说阅读器推荐
  18. [易水寒]大一实训笔记 第二篇
  19. Linux 性能分析
  20. 基于STM32采集PM2.5(ZH03B)传感器数据实验

热门文章

  1. 班章管家稳定放心:五万元应该怎样理财?理财产品怎样选?
  2. node批量修改文件扩展名
  3. APP安装与卸载测试点
  4. 北京积分落户纳税入库时间余额已不足
  5. WLST 命令和变量
  6. 网络安全基础——习题集
  7. STM32F103C8T6使用RTC实现日历读取、设置和输出
  8. [洛谷luogu] P1979 [NOIP2013T6]华容道
  9. matlab提取数据的一部分,matlab处理excel数据【怎么用MATLAB从excel中提取部分数据】...
  10. 牛客练习赛85-哲学家的沉思-(上升子序列变形+树状数组+线段树+离散化+set)