18.函数编程的练习
下面是一些函数编程的练习:
mtping.py内容:
#!/usr/bin/env python
#coding:utf8
import os
def ping(ip):
result = os.system("ping -c2 %s &>/dev/null" %ip)
if result:
print "%s:down " % ip
else:
print "%s:up" % ip
if __name__ == "__main__":
for i in range(1,255):
ipaddr = "172.40.2.%s" % i
ping(ipaddr)
mtping2.py内容:
import os
import threading
def ping(ip):
result = os.system("ping -c2 %s &>/dev/null" %ip)
if result:
print "%s:down " % ip
else:
print "%s:up" % ip
if __name__ == "__main__":
for i in range(1,255):
ipaddr = "172.40.2.%s" % i
t = threading.Thread(target=ping,args=[ipaddr])
ping(ipaddr)
生成随机密码
方法1:用raw_input方式不推荐
#!/usr/bin/env python
#coding:utf8
import random
import string
all_chs = string.letters + string.digits
def gen_pass():
pwd = ''
num = int(raw_input("number: "))
for i in range(num):
ch = random.choice(all_chs)
pwd += ch
print pwd
if __name__ == "__main__":
gen_pass()
方法2:
#!/usr/bin/env python
#coding:utf8
import random
import string
all_chs = string.letters + string.digits
def gen_pass(num=8):
pwd = ''
for i in range(num):
ch = random.choice(all_chs)
pwd += ch
return pwd
if __name__ == "__main__":
print gen_pass(5)
print gen_pass()
print gen_pass(10)
编写 makeTextFile.py 脚本,主要要求如下:
1、编写一个程序,要求用户输入文件名
2、如果文件已存在,要求用户重新输入
3、提示用户输入数据,每行数据先写到列表中
4、将列表数据写入到用户输入的文件名中
方案
首先通过循环不断要求用户输入文件名,如果文件已经存在,要求用户输入新文件名。
然后提示用户输入文件内容,将用户的输入信息保存到一个列表中。最后将列表中的每个字符串尾部都加上行结束标志,并写入文件。
为了程序的跨平台性,可以调用 os.linesep 确定行结束标志。在 Linux 系统中,行结束标志为’\n’;在 Windows 系统中,行结束标志为’\r\n’。
#!/usr/bin/env python
#coding:utf8
import os
def get_fname():
while True:
fname = raw_input("filename: ")
if not os.path.exists(fname):
break
print "%s already exists.Try again" % fname
return fname
def get_contents():
contents = []
while True:
data = raw_input("(Enter to quit)>")
if not data:
break
contents.append(data + '\n')
return contents
def wfile(fname,contents):
fobj = open(fname,'w')
fobj.writelines(contents)
fobj.close()
if __name__ == "__main__":
filename = get_fname()
lines = get_contents()
wfile(filename,lines)
在shell中,可以用这种方式实现远程改密码:
chpwd.sh内容:远程改密码
#!/bin/bash
if [ -z "$3" ];then
echo "Usage: $0 ipfile oldpass newpass"
exit 1
fi
ipfile=$1
oldpass=$2
newpass=$3
if [! -f $ipfile ];then
echo "$ipfile does not exists"
exit 2
fi
for ip in $(cat $ipfile)
do
expect <<EOF
spawn ssh root@$ip "echo $newpass | passwd --stdin root"
expect "(yes/no)?"{
send "yes\r"
expect "password:"
send "$oldpass\r"
} "password:" { send "$oldpass\r"}
expect eof
EOF
done
执行结果:
chmod +x chpwd.sh
./chpwd.sh
./chpwd.sh ipaddr.txt redhat redhat
而在Python中,可以通过paramiko模块实现
chpwd.py内容:远程改密码
方法1:
#!/usr/bin/env python
import sys
import paramiko
def remote_comm(host,pwd,comm):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host,username='root',password=pwd)
stdin,stdout,stderr = ssh.exec_command(comm)
print stdout.read(),
print stderr.read(),
if __name__ == "__main__":
if len(sys.argv) !=4:
print "Usage: %s ipfile oldpass newpass" % sys.argv[0]
else:
ipfile = sys.argv[1]
oldpass = sys.argv[2]
newpass = sys.argv[3]
ch_pwd = "echo %s | passwd --stdin root" % newpass
fobj = open(ipfile)
for line in fobj:
ip = line.strip()
remote_comm(ip,oldpass,ch_pwd)
执行结果:
[root@host-192-168-3-6 test]# chmod +x chpwd.py
[root@host-192-168-3-6 test]# cat ipaddr.txt
192.168.3.6
root@host-192-168-3-6 test]# ./chpwd.py ipaddr.txt abc123 abc123
Changing password for user root.
passwd: all authentication tokens updated successfully.
方法2:mtchpwd.py内容:远程改密码
#!/usr/bin/env python
import sys
import paramiko
import threading
def remote_comm(host,pwd,comm):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host,username='root',password=pwd)
stdin,stdout,stderr = ssh.exec_command(comm)
print stdout.read(),
print stderr.read(),
if __name__ == "__main__":
if len(sys.argv) !=4:
print "Usage: %s ipfile oldpass newpass" % sys.argv[0]
else:
ipfile = sys.argv[1]
oldpass = sys.argv[2]
newpass = sys.argv[3]
ch_pwd = "echo %s | passwd --stdin root" % newpass
fobj = open(ipfile)
for line in fobj:
ip = line.strip()
t = threading.Thread(target=remote_comm,args=(ip,oldpass,ch_pwd))
t.start()
编写 idcheck.py 脚本,主要要求如下:
1、程序接受用户输入
2、用户输入的数据要求大于两个字符
3、判断用户输入的标识符是否合法
方案
合法标识符的要求是:
1、第一个字符必须是字母或下划线
2、其余字符可以是字母、下划线或数字
3、大小写敏感
方法1:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import string
alphas = string.letters + '_'
nums = string.digits
print 'Welcome to my id check prog'
inp = raw_input('Enter a id: ')
if inp[0] not in alphas: #判断首字符是否合法
print 'bad identifier'
else:
for otherchar in inp[1:]: #判断其余字符是否合法
if otherchar not in (alphas + nums):
print 'bad other char'
break
else: #注意此处的 else 是 for 结构的一部分
print '%s is good' % inp
执行结果:
Welcome to my id check prog
Enter a id: 123
bad identifier
方法2:
#!/usr/bin/env python
#coding:utf8
import string
first_chs = string.letters + '_'
other_chs = first_chs + string.digits
def check_id(myid):
if myid[0] not in first_chs:
print "1st char invalid."
return
for ind,ch in enumerate(myid[1:]):
if ch not in other_chs:
print "char in position:%s invalid" % (ind +2)
break
else:
print "%s is valid" % myid
if __name__ == "__main__":
myid = raw_input("id to check: ")
if myid:
check_id(myid)
else:
print "You must input an identifier."
执行结果:
id to check: 124
1st char invalid.
编写 formatoutput.py 脚本,主要要求如下:
1、提示用户输入(多行)数据
2、假定屏幕的宽度为 50,用户输入的多行数据如下显示(文本内容居中) :
方案
为了实现文本内容居中,可以在字符串的两端打印相关的“+”号和空格即可。
字符串每一侧打印的空格数可以使用屏幕宽度减去字符串长度再除以 2 得到。 这里要注
意的是如果字符串的长度为奇数,那么将会少打印一个空格。可以在做除法时,把余数保留
下来,字符串左侧打印的空格数为除法的商值,右侧打印的空格数为商值加余数
方法1:
#!/usr/bin/env python
#coding:utf8
width = 48
data = [] #定义列表用于存储用户数据
while True:
entry = raw_input('enter data(. to quit)> ')
if entry == '.':
break
data.append(entry)
print '+' + '*' * width + '+'
for item in data:
length, extra = divmod((width - len(item)) , 2)
print '+' + ' ' * length + item + ' ' * (length + extra) + '+'
print '+' + '*' * width + '+'
执行结果:
enter data(. to quit)> hello
enter data(. to quit)> great work
enter data(. to quit)> .
+************************************************+
+ hello +
+ great work +
+************************************************+
方法2:
#!/usr/bin/env python
#coding:utf8
def get_contents():
contents = []
while True:
data = raw_input("(Enter to quit)>")
if not data:
break
contents.append(data)
return contents
if __name__ == '__main__':
width = 48
lines = get_contents()
print "+%s+" %('*' * width)
for line in lines:
sp_wid,extra = divmod((width-len(line)),2)
print "+%s%s%s+" % (' ' * sp_wid,line,' ' * (sp_wid+extra))
print "+%s+" % ('*' * width)
(Enter to quit)>hello
(Enter to quit)>great work
(Enter to quit)>
+************************************************+
+ hello +
+ great work +
+************************************************+
创建用户
编写 adduser.py 脚本,主要要求如下:
1、编写一个程序,实现创建用户的功能
2、提示用户输入用户名
3、随机生成 8 位密码
4、创建用户并设置密码
5、发邮件通知用户相关信息
创建用户完成后,需要发送邮件通知。因为每封邮件的内容格式一样,只是用户名和
密码有变化,所以使用字符串模板可以很好的实现该功能。
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import string
import random
import os
allChs = string.letters + string.digits
#以下三行为字符串模板的字符串
patt = """your account is created.
username: $user
password: $pwd"""
def genPwd(num = 8): #生成随机密码函数
pwd = ''
for i in range(num):
pwd += random.choice(allChs)
return pwd
if __name__ == '__main__':
username = raw_input('username: ')
password = genPwd()
os.system('useradd %s' % username)
os.system('echo %s | passwd --stdin %s' % (password, username))
t = string.Template(patt)
os.system("echo '%s' | mail -s 'create user' root" % t.substitute(user = username,pwd = password))
执行结果:
[root@host-192-168-3-6 tarena]#python adduser.py
username: alice
Changing password for user alice.
passwd: all authentication tokens updated successfully.
[root@host-192-168-3-6 tarena]# mail
Heirloom Mail version 12.5 7/5/10. Type ? for help.
"/var/spool/mail/root": 2 messages 1 new
1 root Fri Jun 16 10:31 21/691 "user info"
>N 2 root Sat Jul 29 10:03 20/710 "create user"
&
Message 2:
From root@host-192-168-3-6.localdomain Sat Jul 29 10:03:55 2017
Return-Path: <root@host-192-168-3-6.localdomain>
X-Original-To: root
Delivered-To: root@host-192-168-3-6.localdomain
Date: Sat, 29 Jul 2017 10:03:52 +0800
To: root@host-192-168-3-6.localdomain
Subject: create user
User-Agent: Heirloom mailx 12.5 7/5/10
Content-Type: text/plain; charset=us-ascii
From: root@host-192-168-3-6.localdomain (root)
Status: R
your account is created.
username: alice
password: IHgkunGZ
&
方法2:
#!/usr/bin/env python
#coding:utf8
import sys
import randpass2
import os
import string
contents = """username: ${username}
password: ${password}
"""
t = string.Template(contents)
def adduser(user,passwd,email):
data = t.substitute(username=user,password=passwd)
os.system("useradd %s" % user)
os.system("echo %s| passwd --stdin %s" % (passwd,user))
os.system("echo -e '%s' | mail -s 'user info' %s" % (data,email))
if __name__ == '__main__':
username = sys.argv[1]
pwd = randpass2.gen_pass()
adduser(username,pwd,'root@localhost')
执行结果:
[root@host-192-168-3-6 test]# chmod +x adduser.py
[root@host-192-168-3-6 test]# ./adduser.py jerry
Changing password for user jerry.
passwd: all authentication tokens updated successfully.
注意:randpass2模块是自定义的模块,其中的内容为:
#coding:utf8
import random
import string
all_chs = string.letters + string.digits
def gen_pass(num=8):
pwd = ''
for i in range(num):
ch = random.choice(all_chs)
pwd += ch
return pwd
if __name__ == "__main__":
print gen_pass(5)
print gen_pass()
print gen_pass(10)
用列表构建栈结构
栈是一个后进先出的结构,编写 stack.py 脚本,主要要求如下:
1、编写一个程序,用列表实现栈结构
2、需要支持压栈、出栈、查询功能
方案
列表是可变的数据类型,用它模拟栈结构非常合适。在列表的内建方法中,append()
用于向列表追加元素,pop()用于从列表中弹出元素。pop()可以接受下标作为参数,用于
弹出指定位置的元素,默认弹出的是最后一个元素。
#!/usr/bin/env python
#-*- coding:utf-8 -*-
stack = []
def pushit(): #定义压栈函数
item = raw_input('input item: ').strip()
stack.append(item)
def popit(): #定义出栈函数
if len(stack) == 0:
print '\033[32;1mEmpty stack.\033[0m'
else:
print '\033[32;1mpoped [' + stack.pop() + ']\033[0m'
def viewstack(): #定义查看函数
print '\033[32;1m', stack, '\033[0m'
CMDs = {'p':pushit, 'o':popit, 'v':viewstack} #将函数存储在字典中
def showmenu():
prompt = """(P)ush
p(O)p
(V)iew
(Q)uit
Please input your choice: """
while True:
try:
choice = raw_input(prompt).strip().lower()[0]
except (KeyboardInterrupt, EOFError):
choice = 'q'
if choice not in 'povq':
print 'Invalid input. Try again.'
continue
if choice == 'q':
break
else:
CMDs[choice]() #执行字典中对应的函数
if __name__ == '__main__':
showmenu()
执行结果:
(P)ush
p(O)p
(V)iew
(Q)uit
Please input your choice: p
input item: hello
(P)ush
p(O)p
(V)iew
(Q)uit
Please input your choice: p
input item: world
(P)ush
p(O)p
(V)iew
(Q)uit
Please input your choice: v
['hello', 'world']
(P)ush
p(O)p
(V)iew
(Q)uit
Please input your choice: o
poped [world]
(P)ush
p(O)p
(V)iew
(Q)uit
Please input your choice: q
方法2:
#!/usr/bin/env python
#coding:utf8
stack = []
def pushit():
item = raw_input("item: ")
stack.append(item)
def popit():
if stack:
print "poped item:",stack.pop()
else:
"Empty stack"
def viewit():
print stack
def show_menu():
CMDs = {'0':pushit,'1':popit,'2':viewit}
prompt ='''(0) push it
(1) pop it
(2) view it
(3) quit
Please input your choice(0/1/2/3):'''
while True:
choice = raw_input(prompt).strip()[0]
if choice not in '0123':
print "Invalid input,Try again."
continue
if choice == '3':
break
CMDs[choice]()
if __name__ == "__main__":
show_menu()
rmsps.py内容:
#!/usr/bin/env python
#coding:utf8
#whitespace = '\t\n\v\r\f'
from string import whitespace
def lrmsps(astr):
if not astr:
return astr
for i in range(len(astr)):
if astr[i] not in whitespace:
break
else:
return ''
return astr[i:]
def rrmsps(astr):
if not astr:
return astr
for i in range(-1,-(len(astr)+1),-1):
if astr[i] not in whitespace:
break
else:
return ''
return astr[:(i+1)]
def rmsps(astr):
return rrmsps(lrmsps(astr))
if __name__ == '__main__':
hi = " hello \t"
print "|%s|" % lrmsps(hi)
print "|%s|" % rrmsps(hi)
print "|%s|" % rmsps(hi)
执行结果:
|hello | | hello| |hello|
rmsps2.py内容:
#!/usr/bin/env python
#coding:utf8
from string import whitespace
def lrmsps(astr):
str_list = list(astr)
for i in range(len(str_list)):
if str_list[0] not in whitespace:
break
str_list.pop(0)
return ''.join(str_list)
def rrmsps(astr):
str_list = list(astr)
for i in range(len(str_list)):
if str_list[-1] not in whitespace:
break
str_list.pop()
return ''.join(str_list)
def rmsps(astr):
return lrmsps(rrmsps(astr))
if __name__ == '__main__':
hi = ' hello \t'
print "|%s|" % lrmsps(hi)
print "|%s|" % rrmsps(hi)
print "|%s|" % rmsps(hi)
执行结果:
|hello | | hello| |hello|
convertip.py内容:
#!/usr/bin/env python
#coding:utf8
def int2ip(num):
ip_list = []
for i in range(4):
num,mod = divmod(num, 256)
ip_list.insert(0,str(mod))
return '.'.join(ip_list)
def ip2int(ip):
ip_list = ip.split('.')
num = 0
for i in range(len(ip_list)):
num += int(ip_list[i]) * 256 ** (3-i)
return num
if __name__ == "__main__":
print int2ip(3232235786)
print ip2int('192.168.1.10')
执行结果:
192.168.1.10
3232235786
用户登陆信息系统
编写 ulogin.py 脚本,主要要求如下:
1、使用字典模拟一个用户登陆信息系统
2、支持新用户注册,新用户名和密码注册到字典中
3、支持老用户登陆,用户名和密码正确提示登陆成功
4、主程序通过循环询问进行何种操作,根据用户的选择,执行注册或是登陆操作
方案
因为没有永久存储,不能把用户名和密码永久保存下来,所以在编写程序时,应该使用循环结构保证程序不要退出。
在字典里,将 key 设置为用户名,value 设置为密码
方法1:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import getpass
db = {} #定义用于用户信息的字典
def newUser(): #定义新用户注册函数
username = raw_input('username: ')
if username in db:
print "\033[32;1m%s alread exists!\033[0m" % username
else:
password = getpass.getpass()
db[username] = password
def oldUser(): #定义老用户登陆函数
username = raw_input('username: ')
password = getpass.getpass() #不在屏幕上显示密码
if username in db:
if db[username] == password:
print '\033[32;1mlogin successful!\033[0m'
else:
print '\033[32;1mlogin incorrect.\033[0m'
else:
print '\033[32;1mlogin incorrect.\033[0m'
CMDs = {'n': newUser, 'o': oldUser} #将函数存放在字典中
def showMenu():
prompt = """(N)ew user
(O)ld user
(Q)uit
please input your choice: """
while True:
try:
choice = raw_input(prompt).strip()[0].lower()
except (KeyboardInterrupt, EOFError):
choice = 'q'
if choice not in 'noq':
print '\033[31;1mInvalid option.Try again(n / o / q).\033[0m'
continue
if choice == 'q':
break
CMDs[choice]()
if __name__ == '__main__':
showMenu()
执行结果:
[root@host-192-168-3-6 tarena]# python ulogin.py
(N)ew user
(O)ld user
(Q)uit
please input your choice: n
username: tom
Password:
(N)ew user
(O)ld user
(Q)uit
please input your choice: n
username: tom
tom alread exists!
(N)ew user
(O)ld user
(Q)uit
please input your choice: o
username: tom
Password:
login successful!
(N)ew user
(O)ld user
(Q)uit
please input your choice: q
方法2:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import getpass
db = {}
def new_user():
user = raw_input("username: ")
pwd = raw_input("password: ")
# if user not in db:
# db[user] ==pwd
if pwd == db.setdefault(user,pwd):
print "Register successful"
else:
print "%s already exists." % user
def olduser():
user = raw_input("username: ")
pwd = getpass.getpass("password: ")
#if user not in db or db[user] != pwd:
if db.get(user) != pwd:
print "Login incorrect."
else:
print "Login successful."
def show_menu():
CMDs = {'0':new_user,'1':olduser}
prompt = """(0)new user
(1)old user
(2)quit
Please input your choice(0/1/2):"""
while True:
choice = raw_input(prompt).strip()[0]
if choice not in '012':
print "Invalid choice.Try again.."
continue
if choice == '2':
break
CMDs[choice]()
if __name__ == "__main__":
show_menu()
执行结果:
[root@host-192-168-3-6 tarena]# python ulogin2.py
(0)new user
(1)old user
(2)quit
Please input your choice(0/1/2):0
username: tom
password: 123456
Register successful
(0)new user
(1)old user
(2)quit
Please input your choice(0/1/2):1
username: tom
password:
Login successful.
(0)new user
(1)old user
(2)quit
Please input your choice(0/1/2):q
Invalid choice.Try again..
(0)new user
(1)old user
(2)quit
Please input your choice(0/1/2):2
模拟 case 句法
编写 case.py 脚本,主要要求如下:
提示用户输入执行何种操作(create/delete/modify)
1、如果输入为 create,则打印 create user
2、如果输入为 delete,则打印 delete user
3、如果输入为 modify,则打印 modify user
4、否则打印 input error
方案:
python 中没有 case/switch 语句,但是可以使用其他的结构进行模拟。利用列表、
元组、字典等数据结构都可以实现 case 语句的功能。
本例使用字典的方法进行 case 功能模拟
方法1:
#!/usr/bin/env python
db = {'create' : 'create', 'delete' : 'delete', 'modify' : 'modify'}
prompt = """create
delete
modify
please input your choice: """
choice = raw_input(prompt)
if db.get(choice):
print db[choice], 'user'
else:
print 'input error'
执行结果:
create
delete
modify
please input your choice: create
create user
方法2:
#!/usr/bin/env python
#coding:utf8
import sys
ops = ['create','modify','delete']
op = sys.argv[1]
if op in ops:
print "%s user" % op
else:
print "Usage: create | modify | delete user"
执行结果:
[root@host-192-168-3-6 tarena]# chmod +x case.py
[root@host-192-168-3-6 tarena]# ./case.py tom
Usage: create | modify | delete user
实现系统中unix2dos命令的功能
方法1:
#!/usr/bin/env python
#coding:utf8
import os
import sys
def unix2dos(fname):
dfname = os.path.splitext(fname)[0] + '.win'
src_fobj = open(fname)
dst_fobj = open(dfname,'w')
for line in src_fobj:
dst_fobj.write(line.rstrip('\n\r') + '\r\n')
src_fobj.close()
dst_fobj.close()
if __name__ == '__main__':
if len(sys.argv) != 2:
print "Usage: %s filename " % sys.argv[0]
sys.exit(1)
filename = sys.argv[1]
if not os.path.isfile(filename):
print "No such file: %s" % filename
sys.exit(2)
unix2dos(filename)
执行结果:
{root@host-192-168-3-6 test]# python u2d.py
Usage: u2d.py filename
[root@host-192-168-3-6 test]# vim abc.txt
abcdeef
hello
[root@host-192-168-3-6 test]# python u2d.py abc.txt
[root@host-192-168-3-6 test]# ls
abc.txt
abc.win
方法2:
#!/usr/bin/env python
#coding:utf8
import sys
def unix2dos(fname,sep='\r\n'):
dst_name = fname + '.txt'
with open(fname) as src_fobj:
with open(dst_name,'w') as dst_fobj:
for line in src_fobj:
dst_fobj.write("%s%s" % (line.rstrip('\r\n'),sep))
if __name__ == "__main__":
unix2dos(sys.argv[1])
执行结果:
[root@host-192-168-3-6 ~]# python u2d.py myadd.py
root@host-192-168-3-6 ~]# ls
myadd.py
myadd.py.txt
u2d.py
>>> with open('myadd.py') as f1:
... f1.readline()
...
'#!/usr/bin/env python\n'
>>> with open('myadd.py.txt') as f1:
... f1.readline()
...
'#!/usr/bin/env python\r\n'
>>>
实现系统中dos2unix命令的功能
方法1:
#!/usr/bin/env python
#coding:utf8
import os
import sys
def dos2unix(fname):
dfname = os.path.splitext(fname)[0] + '.unix'
src_fobj = open(fname)
dst_fobj = open(dfname,'w')
for line in src_fobj:
dst_fobj.write(line.rstrip('\n\r') + '\n')
src_fobj.close()
dst_fobj.close()
if __name__ == '__main__':
if len(sys.argv) != 2:
print "Usage: %s filename " % sys.argv[0]
sys.exit(1)
filename = sys.argv[1]
if not os.path.isfile(filename):
print "No such file: %s" % filename
sys.exit(2)
dos2unix(filename)
方法2:
#!/usr/bin/env python
#coding:utf8
import sys
import u2d
from functools import partial
dos2unix = partial(u2d.unix2dos,sep = '\n')
if __name__ == '__main__':
dos2unix(sys.argv[1])
执行结果:
[root@host-192-168-3-6 ~]# python d2u.py myadd.py.txt
[root@host-192-168-3-6 ~]# ls
myadd.py
myadd.py.txt
d2u.py
myadd.py.txt.txt
u2d.py
>>> with open('myadd.py.txt.txt') as f3:
... f3.readline()
...
'#!/usr/bin/env python\n'
>>>
编写 mathgame.py 脚本,主要要求如下:
随机生成两个 100 以内的数字
1、随机选择加法或是减法
2、总是使用大的数字减去小的数字
3、如果用户答错三次,程序给出正确答案
方案
程序中要求不断的出题,为了减少代码的冗余以及实现代码的重用,可以把代码放入函数中。
随机取得数字可以使用 random.choice(),取出来的数字放到列表中,为了总是使用
大数减去小数,需要再给列表排序
#!/usr/bin/env python
#coding:utf-8
from operator import add, sub
from random import randint, choice
ops = {'+': add, '-': sub} #将 add 和 sub 函数放到字典中
MAXTRIES = 2
def doprob():
op = choice('+-')
nums = [randint(1, 100) for i in range(2)] #使用列表解析,生成数字列表
nums.sort(reverse = True) #将列表按降序方式排序
ans = ops[op](*nums) #此处*nums 用于将列表解开,得到数字
pr = '%d %s %d = ' % (nums[0], op, nums[1])
oops = 0 #定义错误计数器
while True:
try:
if int(raw_input(pr)) == ans:
print 'correct'
break
if oops == MAXTRIES:
print 'answer\n%s%d' % (pr, ans)
break
else:
print 'incorrect... try again.'
oops += 1
except (KeyboardInterrupt, EOFError, ValueError):
print 'invalid input... try again.'
def main():
while True:
doprob()
try:
opt = raw_input('Again?[y]?').lower()
if opt and opt[0] == 'n':
break
except (KeyboardInterrupt, EOFError):
break
if __name__ == '__main__':
main()
方法1:
执行结果:
[root@host-192-168-3-6 tarena]# python mathgame.py
36 - 29 = 7
correct
Again?[y]?n
方法2:
#!/usr/bin/env python
#coding:utf8
import random
def add(x,y):
return x + y
def sub(x,y):
return x - y
def probe():
CMDs = {'+':add,'-':sub}
nums = [random.randint(1,50) for i in range(2)]
nums.sort(reverse=True)
op = random.choice('+-')
answer = CMDs[op](*nums)
prompt = "%s%s%s = " % (nums[0],op,nums[1])
tries = 0
while tries <3:
result = int(raw_input(prompt))
if answer == result:
print "Very Good!!!"
break
print "Wrong answer..."
tries += 1
else:
print "\033[31;1m%s%s\033[0m" % (prompt,answer)
if __name__ == "__main__":
while True:
probe()
yn = raw_input("Continue(y/n)? ").strip()[0]
if yn in 'nN':
break
执行结果:
39-25 = 14
Very Good!!!
Continue(y/n)? n
方法3:
#!/usr/bin/env python
#coding:utf8
import random
def add(x,y):
return x + y
def sub(x,y):
return x - y
def probe():
CMDs = {'+':add,'-':sub}
nums = [random.randint(1,50) for i in range(2)]
nums.sort(reverse=True)
op = random.choice('+-')
answer = CMDs[op](*nums)
prompt = "%s%s%s = " % (nums[0],op,nums[1])
tries = 0
while tries <3:
try:
result = int(raw_input(prompt))
except:
continue
if answer == result:
print "Very Good!!!"
break
print "Wrong answer..."
tries += 1
else:
print "\033[31;1m%s%s\033[0m" % (prompt,answer)
if __name__ == "__main__":
while True:
probe()
try:
yn = raw_input("Continue(y/n)? ").strip()[0]
except (KeyboardInterrupt,EOFError):
print "\nBye Bye"
yn = 'n'
except IndexError:
continue
if yn in 'nN':
break
执行结果:
29+13 = 42
Very Good!!!
Continue(y/n)? 123
42-29 = 13
Very Good!!!
Continue(y/n)? y
32-4 = 28
Very Good!!!
Continue(y/n)? n
方法4:
#!/usr/bin/env python
#coding:utf8
import random
'''
def add(x,y):
return x + y
def sub(x,y):
return x - y
'''
def probe():
#CMDs = {'+':add,'-':sub}
CMDs = {'+':lambda x,y:x+y,'-':lambda x,y:x-y}
nums = [random.randint(1,50) for i in range(2)]
nums.sort(reverse=True)
op = random.choice('+-')
answer = CMDs[op](*nums)
prompt = "%s%s%s = " % (nums[0],op,nums[1])
tries = 0
while tries <3:
try:
result = int(raw_input(prompt))
except:
continue
if answer == result:
print "Very Good!!!"
break
print "Wrong answer..."
tries += 1
else:
print "\033[31;1m%s%s\033[0m" % (prompt,answer)
if __name__ == "__main__":
while True:
probe()
try:
yn = raw_input("Continue(y/n)? ").strip()[0]
except (KeyboardInterrupt,EOFError):
print "\nBye Bye"
yn = 'n'
except IndexError:
continue
if yn in 'nN':
break
执行结果:
38-12 = 26
Very Good!!!
Continue(y/n)? n
func1.py内容:
!/usr/bin/env python
#coding:utf8
def func1(x):
return x % 2
def func2(x):
return x **2
def func3(x,y):
return x + y
if __name__ == "__main__":
print filter(func1,range(1,11))
print filter(lambda x:x %2,range(1,11))
print map(func2,range(1,11))
print map(lambda x: x**2,range(1,11))
print reduce(func3,range(1,11))
print reduce(lambda x,y: x+y,range(1,11))
执行结果:
[1, 3, 5, 7, 9]
[1, 3, 5, 7, 9]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
55
55
递归列出目录:
[root@host-192-168-3-6 ~]# cd /home/
[root@host-192-168-3-6 home]# mkdir -p demo/{aaa/bbb,ccc}
[root@host-192-168-3-6 home]# ls
centos demo jerry list mytouch zhuji
[root@host-192-168-3-6 home]# ls demo/
aaa ccc
[root@host-192-168-3-6 home]# ls demo/aaa/
bbb
[root@host-192-168-3-6 home]# cp /etc/hosts demo/
[root@host-192-168-3-6 home]# touch demo/d.txt
[root@host-192-168-3-6 home]# touch demo/aaa/{a1,a2}.txt
[root@host-192-168-3-6 home]# ls demo/aaa/
a1.txt a2.txt bbb
[root@host-192-168-3-6 home]# touch demo/aaa/bbb/b.txt
[root@host-192-168-3-6 home]# touch demo/ccc/{c1,c2}.txt
[root@host-192-168-3-6 home]# ls -R demo/
demo/:
aaa ccc d.txt hosts
demo/aaa:
a1.txt a2.txt bbb
demo/aaa/bbb:
b.txt
demo/ccc:
c1.txt c2.txt
[root@host-192-168-3-6 home]#
方法1:lsdir.py内容:
#!/usr/bin/env python
#coding:utf8
import os
import sys
def lsdir(folder):
contents = os.listdir(folder)
print "%s:\n%s\n" % (folder,contents)
for item in contents:
full_path = os.path.join(folder,item)
if os.path.isdir(full_path):
lsdir(full_path)
if __name__ == "__main__":
lsdir(sys.argv[1])
执行结果:
[root@host-192-168-3-6 ~]# python lsdir.py /home/demo/
/home/demo/:
['aaa', 'ccc', 'hosts', 'd.txt']
/home/demo/aaa:
['bbb', 'a1.txt', 'a2.txt']
/home/demo/aaa/bbb:
['b.txt']
/home/demo/ccc:
['c2.txt', 'c1.txt']
方法2:
step1:
> import os
>>> import tab
>>> os.wa
os.wait( os.wait3( os.wait4( os.waitpid( os.walk(
>>> os.walk('/home/demo')
<generator object walk at 0x7ff99ff2eeb0>
>>> list(os.walk('/home/demo'))
[('/home/demo', ['aaa', 'ccc'], ['hosts', 'd.txt']), ('/home/demo/aaa', ['bbb'], ['a1.txt', 'a2.txt']), ('/home/demo/aaa/bbb', [], ['b.txt']), ('/home/demo/ccc', [], ['c2.txt', 'c1.txt'])]
>>> a = os.walk('/home/demo')
>>> a.next()
('/home/demo', ['aaa', 'ccc'], ['hosts', 'd.txt'])
>>> a.next()
('/home/demo/aaa', ['bbb'], ['a1.txt', 'a2.txt'])
>>> a.next()
('/home/demo/aaa/bbb', [], ['b.txt'])
>>> a.next()
('/home/demo/ccc', [], ['c2.txt', 'c1.txt'])
>>> a.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
step2:lsdir2.py内容
#!/usr/bin/env python
#coding:utf8
import os
import sys
def lsdir(folder):
for path,dirs,files in os.walk(folder):
print "%s:\n%s\n" % (path,(dirs + files))
if __name__ == "__main__":
lsdir(sys.argv[1])
[root@host-192-168-3-6 ~]# python lsdir2.py /home/demo/
/home/demo/:
['aaa', 'ccc', 'hosts', 'd.txt']
/home/demo/aaa:
['bbb', 'a1.txt', 'a2.txt']
/home/demo/aaa/bbb:
['b.txt']
/home/demo/ccc:
['c2.txt', 'c1.txt']
模拟 cp 操作
方案
“拷贝”一个文件,可以首先在目标位置创建一个空文件,然后再将源文件读出,写入到新文件中。
打开文件时并不消耗太多内存,但是将文件内容读到变量中,会根据读入的数据大小消耗相应的内存。
为了防止一次性读入大文件消耗太多的内存,可以采用循环的方式,多次少量读取数据
注意:方法1和方法2可在文件和输入输出章节查看
方法3:函数方式
#!/usr/bin/env python
#coding:utf8
def cp():
sfname = '/bin/ls'
dfname = '/root/ls'
src_fobj = open(sfname)
dst_fobj = open(dfname,'w')
while True:
data = src_fobj.read(4096)
if not data:
break
dst_fobj.write(data)
src_fobj.close()
dst_fobj.close()
cp()
方法4:
cp.py带参数:
#!/usr/bin/env python
#coding:utf8
def cp(sfname,dfname):
src_fobj = open(sfname)
dst_fobj = open(dfname,'w')
while True:
data = src_fobj.read(4096)
if not data:
break
dst_fobj.write(data)
src_fobj.close()
dst_fobj.close()
cp('/bin/ls','/home/list')
cp('/bin/touch','/home/mytouch')
执行过程及结果:
cd /home/
[root@host-192-168-3-6 home]# ls
centos
[root@host-192-168-3-6 home]# cd centos/
[root@host-192-168-3-6 test]# python zgy.py
[root@host-192-168-3-6 test]# cd -
/home
[root@host-192-168-3-6 home]# ls
centos list mytouch
方法5:
#!/usr/bin/env python
#coding:utf8
import sys
def cp(sfname,dfname):
src_fobj = open(sfname)
dst_fobj = open(dfname,'w')
while True:
data = src_fobj.read(4096)
if not data:
break
dst_fobj.write(data)
src_fobj.close()
dst_fobj.close()
cp(sys.argv[1],sys.argv[2])
执行过程及结果:
[root@host-192-168-3-6 test]# python cp.py /etc/hosts
hosts hosts.allow hosts.deny
[root@host-192-168-3-6 test]# python zgy.py /etc/hosts /home/zhuji
[root@host-192-168-3-6 test]# cd /home/
[root@host-192-168-3-6 home]# cat zhuji
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@host-192-168-3-6 home]#
练习:利用cPickle模块
编写一个家庭理财系统。记录你的收支情况。首先,假设你有1万存款,以它作为基数,存钱、花钱都要明确的记录。
时间 存钱 花钱 余额 备注
分析:
1、需要两个记录文件,一个文件当成钱包文件(balance.txt),里面存放着你的最新余额,另一个是记帐本文件(record.txt)
2、为了每次测试方便,使用一个初始化文件(init_money.py),向钱包文件中写入10000
3、主程序文件(finance.py),要有四个基础函数,一个用于存钱(saveMoney),一个用于花钱(spendMoney),一个用于记帐(logger),一个用于查询(queryInfo)
4、主程序运行时,打印一个菜单,询问用户要做什么。获取用户行为后,调用相应的函数。
方法1:
step1:
root@host-192-168-3-6 ~]# cd tarena/
[root@host-192-168-3-6 tarena]# mkdir test
[root@host-192-168-3-6 tarena]# cd test
[root@host-192-168-3-6 test]# ls
initm.py
initm.py内容:
#!/usr/bin/env python
import cPickle as p
fd = file('balance.txt', 'w')
p.dump(10000, fd)
fd.close()
fobj = file('record.txt', 'w')
fobj.close()
执行initm.py
[root@host-192-168-3-6 test]# python initm.py
[root@host-192-168-3-6 test]# ls
balance.txt initm.py record.txt
[root@host-192-168-3-6 test]# vim balance.txt
I10000
step2:新建finance.py
#!/usr/bin/env python
import sys
import cPickle as p
def spendMoney():
spend_date = raw_input('time: ')
spend_money = int(raw_input('how much: '))
spend_comment = raw_input('detail: ')
fd = file('balance.txt')
balance = p.load(fd)
fd.close()
balance -= spend_money
fd = file('balance.txt', 'w')
p.dump(balance, fd)
fd.close()
logger(spend_date, spend_comment, balance, spend_money)
def saveMoney():
save_date = raw_input('time: ')
save_money = int(raw_input('how much: '))
save_comment = raw_input('detail: ')
fd = file('balance.txt')
balance = p.load(fd)
fd.close()
balance += save_money
fd = file('balance.txt', 'w')
p.dump(balance, fd)
fd.close()
logger(save_date, save_comment, balance, amount_save = save_money)
def queryInfo():
fobj = file('record.txt')
print "%-15s%-8s%-8s%-8s%-30s" % ('time', 'kaixiao', 'save', 'balance', 'detail')
for eachLine in fobj:
print eachLine,
fobj.close()
def logger(log_time, comment, new_balance, amount_spend = '', amount_save = ''):
fd = file('record.txt', 'a')
fd.write('%-15s%-8s%-8s%-8s%-30s\n' % (log_time, amount_spend, amount_save, new_balance, comment))
fd.close()
CMDs = {'s': spendMoney, 'v':saveMoney, 'q':queryInfo}
def main():
prompt = """\033[32;1m(S)pend money
sa(V)e money
(Q)uery infomation
(E)xit
Enter your choice: \033[0m"""
while True:
while True:
choice = raw_input(prompt).strip()[0].lower()
if choice not in 'svqe':
print 'invalid input. try again(s v q e).'
continue
else:
break
if choice == 'e':
sys.exit()
else:
CMDs[choice]()
if __name__ == '__main__':
main()
执行finance.py
root@host-192-168-3-6 test]# python finance.py
(S)pend money
sa(V)e money
(Q)uery infomation
(E)xit
Enter your choice: v
time: 2017-07-31
how much: 2000
detail: abc
(S)pend money
sa(V)e money
(Q)uery infomation
(E)xit
Enter your choice: q
time kaixiao save balance detail
2017-07-31 2000 12000 abc
(S)pend money
sa(V)e money
(Q)uery infomation
(E)xit
Enter your choice: s
time: 2017-07-31
how much: 1000
detail: shopping
(S)pend money
sa(V)e money
(Q)uery infomation
(E)xit
Enter your choice: q
time kaixiao save balance detail
2017-07-31 2000 12000 abc
2017-07-31 1000 11000 shopping
(S)pend money
sa(V)e money
(Q)uery infomation
(E)xit
Enter your choice: e
[root@host-192-168-3-6 test]#
方法2:
step1:
initm.py内容:
#!/usr/bin/env python
import cPickle as p
with open('record.txt', 'w') as record:
pass
with open('balance.txt', 'w') as f:
p.dump(10000, f)
执行initm.py
[root@host-192-168-3-6 test]# python initm.py
[root@host-192-168-3-6 test]# ls
balance.txt initm.py record.txt
[root@host-192-168-3-6 test]# vim balance.txt
I10000
step2:新建finance.py
#!/usr/bin/env python
#coding:utf-8
import sys
import time
import cPickle as p
walletfile = '/root/tarena/test/balance.txt' #绝对路径下的文件
recordfile = '/root/tarena/test/record.txt'
def spendMoney():
amount = int(raw_input('数额:'))
comment = raw_input('用途:')
with file(walletfile) as f:
newbalance = p.load(f) - amount
with file(walletfile,'w') as f:
p.dump(newbalance,f)
logger('',amount,newbalance,comment)
def saveMoney():
amount = int(raw_input('数额:'))
comment = raw_input('来源:')
with file(walletfile) as f:
newbalance = p.load(f) + amount
with file(walletfile,'w') as f:
p.dump(newbalance,f)
logger(amount,'',newbalance,comment)
def queryInfo():
print "%-14s%-9s%-9s%-9s%-19s" % ('时间','存入','支出','余额','备注')
with file(recordfile) as f:
for eachLine in f:
print eachLine,
def logger(saM,spM,nb,cm):
result = "%-12s%-7s%-7s%-7s%-17s\n" % (time.strftime('%Y-%m-%d'),saM,spM,nb,cm)
with file(recordfile,'a') as f:
f.write(result)
CMDs = {'s': spendMoney, 'v':saveMoney, 'q':queryInfo}
def showmenu():
prompt = """(s)支出
(v)收入
(q)查询
(e)退出
请输入您的选择(s/v/q/e): """
while True:
choice = raw_input(prompt).strip()[0].lower()
if choice not in 'svqe':
print '\033[31;1m无效的选择,请重试.\033[0m'
continue
if choice == 'e':
break
else:
CMDs[choice]()
if __name__ == '__main__':
showmenu()
执行结果:
[root@host-192-168-3-6 test]# python finance.py
(s)支出
(v)收入
(q)查询
(e)退出
请输入您的选择(s/v/q/e): q
时间 存入 支出 余额 备注
(s)支出
(v)收入
(q)查询
(e)退出
请输入您的选择(s/v/q/e): v
数额:10000
来源:abc
(s)支出
(v)收入
(q)查询
(e)退出
请输入您的选择(s/v/q/e): q
时间 存入 支出 余额 备注
2017-07-31 10000 20000 abc
(s)支出
(v)收入
(q)查询
(e)退出
请输入您的选择(s/v/q/e): s
数额:1000
用途:shopping
(s)支出
(v)收入
(q)查询
(e)退出
请输入您的选择(s/v/q/e): q
时间 存入 支出 余额 备注
2017-07-31 10000 20000 abc
2017-07-31 1000 19000 shopping
(s)支出
(v)收入
(q)查询
(e)退出
请输入您的选择(s/v/q/e): e
[root@host-192-168-3-6 test]#
方法3:
#!/usr/bin/env python
#coding:utf8
import os
import cPickle as p
import time
def spend_money(wallet,record,date,amount,comment):
with open(wallet) as fobj:
balance = p.load(fobj) - amount
with open(wallet,'w') as fobj:
p.dump(balance,fobj)
with open(record,'a') as fobj:
fobj.write(
"%-12s%-8s%-8s%-10s%-20s\n" % (date,amount,'N/A',balance,comment)
)
def save_money(wallet,record,date,amount,comment):
with open(wallet) as fobj:
balance = p.load(fobj) + amount
with open(wallet,'w') as fobj:
p.dump(balance,fobj)
with open(record,'a') as fobj:
fobj.write(
"%-12s%-8s%-8s%-10s%-20s\n" % (date,'N/A',amount,balance,comment)
)
def query_money(wallet,record):
print "%-12s%-8s%-8s%-10s%-20s\n" % \
('date','spend','save','balance','comment')
with open(record) as fobj:
for line in fobj:
print line,
with open(wallet) as fobj:
print "New Balance: \n%s" % p.load(fobj)
def show_menu(wallet,record):
CMDs = {'0':spend_money,'1':save_money,'2':query_money}
prompt = """(0)spend money
(1)save money
(2)query money
(3)quit
Please input your choice(0/1/2/3):"""
while True:
try:
choice = raw_input(prompt).strip()[0]
except IndexError:
continue
except (KeyboardInterrupt,EOFError):
choice = '3'
if choice not in '0123':
print "Invalid choice ,Try again"
continue
if choice == '3':
print "Bye-bye"
break
args = (wallet,record)
if choice in '01':
date = time.strftime("%Y%m%d")
try:
amount = int(raw_input("amount: "))
comment = raw_input("comment: ")
except ValueError:
print "Invalid number.Try again."
continue
except (KeyboardInterrupt,EOFError):
print "\nBye-bye"
break
args = (wallet,record,date,amount,comment)
CMDs[choice](*args)
if __name__ == "__main__":
wallet = 'wallet.data'
record = "record.txt"
if not os.path.exists(wallet):
with open(wallet,'w') as fobj:
p.dump(10000, fobj)
if not os.path.exists(record):
os.mknod(record)
show_menu(wallet,record)
执行结果:
[root@host-192-168-3-6 test]# ls
finance.py
[root@host-192-168-3-6 test]# python finance.py
(0)spend money
(1)save money
(2)query money
(3)quit
Please input your choice(0/1/2/3):1
amount: 10000
comment: abc
(0)spend money
(1)save money
(2)query money
(3)quit
Please input your choice(0/1/2/3):2
date spend save balance comment
20170801 N/A 10000 20000 abc
New Balance:
20000
(0)spend money
(1)save money
(2)query money
(3)quit
Please input your choice(0/1/2/3):0
amount: 1000
comment: shopping
(0)spend money
(1)save money
(2)query money
(3)quit
Please input your choice(0/1/2/3):q
Invalid choice ,Try again
(0)spend money
(1)save money
(2)query money
(3)quit
Please input your choice(0/1/2/3):2
date spend save balance comment
20170801 N/A 10000 20000 abc
20170801 1000 N/A 19000 shopping
New Balance:
19000
(0)spend money
(1)save money
(2)query money
(3)quit
Please input your choice(0/1/2/3):3
Bye-bye
[root@host-192-168-3-6 test]# ls
finance.py record.txt wallet.data
[root@host-192-168-3-6 test]#
备份程序
编写 backup.py 脚本,主要要求如下:
1、需要支持完全和增量备份
2、周一执行完全备份
3、其他时间执行增量备份
4、备份文件需要打包为 tar 文件并使用 gzip 格式压缩
方案
备份要求采用 tar 包的方式打包并用 gzip 压缩,python 的 tarfile 模块提供了该功能。
Tarfile 模块即可以支持普通的打包功能,还可以调用 gzip 或 bzip2 实现压缩、解压缩的功能。
为了实现增量备份,需要知道哪些文件是已经改动过了,改动过的文件才需要备份。
判断一个文件是否改动过,可以计算文件的 md5 值,如果 md5 值有变化则表明文件已改,否则为未修改。python 的 hashlib 模块提供了计算 md5 值的方法
在计算 md5 值时,有些文件可能非常大,不应该直接将文件全部读入内存,而应该使用循环的方式分部分更新。md5 值每天增量备份时都需要使用,必须将其永久的保存下来,
可以使用 cPickle 永久存储器实现该功能。把文件的 md5 值存入字典,再将字典存入到cPickle 永久存储器中。
每天都可能会产生一个增量备份文件,为了保证文件名不冲突又便于识别,可以采用基础名加日期的命名方式。
以下步骤假设要备份的目录为/home/demo/src,备份的目标目录为/home/demo/dst。
方法1:
步骤一:编写脚本
#!/usr/bin/env python
#coding:utf-8
import time
import hashlib
import tarfile
import os
import cPickle
basedir = '/home/demo'
srcdir = 'src'
dstdir = 'dst'
md5file = os.path.join(basedir, dstdir, 'md5.data') #md5 文件位置
fullname = 'full_src%s.tar.gz' % (time.strftime('%Y%m%d')) #完全备份文件名
incname = 'incr_src%s.tar.gz' % (time.strftime('%Y%m%d')) #增量备份文件名
def fullBackup(): #完全备份函数
os.chdir(basedir)
tar = tarfile.open(os.path.join(basedir, dstdir, fullname), 'w:gz')
tar.add(srcdir)
tar.close()
md5dict = {} #计算文件 md5 值
for eachFile in os.listdir(os.path.join(basedir, srcdir)):
fullpath = os.path.join(basedir, srcdir, eachFile)
md5dict[eachFile] = md5sum(fullpath)
with open(md5file, 'w') as f: #存储文件 md5 值到 cPicle 存储器
cPickle.dump(md5dict, f)
def incrBackup(): #增量备份函数
with open(md5file) as f:
storedmd5 = cPickle.load(f)
newmd5 = {}
for eachFile in os.listdir(os.path.join(basedir, srcdir)):
fullpath = os.path.join(basedir, srcdir, eachFile)
newmd5[eachFile] = md5sum(fullpath)
tar = tarfile.open(os.path.join(basedir, dstdir, incname), 'w:gz')
os.chdir(basedir)
for eachKey in newmd5:
if (eachKey not in storedmd5) or (newmd5[eachKey] != storedmd5[eachKey]):
tar.add(os.path.join(srcdir, eachKey))
tar.close()
with open(md5file, 'w') as f:
cPickle.dump(newmd5, f)
def md5sum(fname): #md5 值计算函数
m = hashlib.md5()
with open(fname) as f:
while True:
data = f.read(4096)
if len(data) == 0:
break
m.update(data)
return m.hexdigest()
def main():
if time.strftime('%a') == 'Mon': #如果是周一执行完全备份,否则执行增量备份
fullBackup()
else:
incrBackup()
if __name__ == '__main__':
main()
step2:
[root@host-192-168-3-6 test]# mkdir /home/demo/
[root@host-192-168-3-6 test]# cd /home/demo/
[root@host-192-168-3-6 demo]# mkdir dst
[root@host-192-168-3-6 demo]# mkdir src
[root@host-192-168-3-6 demo]# cd -
/root/tarena/test
[root@host-192-168-3-6 test]#
[root@host-192-168-3-6 test]# python backup.py
[root@host-192-168-3-6 test]# ls
backup.py finance.py record.txt wallet.data
[root@host-192-168-3-6 test]# cd /home/demo/
[root@host-192-168-3-6 demo]# ls
aaa ccc dst d.txt hosts passwd redhat-release shadow src
[root@host-192-168-3-6 demo]# cd src/
[root@host-192-168-3-6 src]# ls
[root@host-192-168-3-6 src]# cd ../dst/
[root@host-192-168-3-6 dst]# ls
full_src20170801.tar.gz md5.data
[root@host-192-168-3-6 dst]#
step3:测试脚本执行
[root@py01 bin]# crontab –e
00 01 * * * /root/bin/backup.py
方法2:
step1:
>>> afile = "/home/demo/aaa/a.txt"
>>> afile.split('/home')
['', '/demo/aaa/a.txt']
>>> afile.split("home")[1]
'/demo/aaa/a.txt'
>>> afile.split("home")[1].lstrip('/')
'demo/aaa/a.txt'
>>>
step2:编写脚本
#!/usr/bin/env python
#coding:utf8
import time
import os
import tarfile
import cPickle as p
import hashlib
def check_md5(fname):
#计算文件md5值,为了防止文件太大,占用内存,每次计算4096字节
m = hashlib.md5()
with open(fname) as fobj:
while True:
data = fobj.read(4096)
if not data:
break
m.update(data)
return m.hexdigest()
def full_backup(src_dir,dst_dir,md5file):
"""首先,切割源目录,将要备份的目录及其所在的目录分开
目标名称:demo_full_20160411.tar.gz,再生成绝对路径
"""
md5dict = {}
base_dir,back_dir = os.path.split(src_dir.rstrip('/'))
back_name = "%s_full_%s.tar.gz" % (back_dir,time.strftime("%Y%m%d"))
full_path = os.path.join(dst_dir,back_name)
os.chdir(base_dir)
tar = tarfile.open(full_path,"w:gz")
tar.add(back_dir)
tar.close()
for path,dirs,files in os.walk(src_dir):
for each_file in files:
full_name = os.path.join(path,each_file)
md5dict[full_name] = check_md5(full_name)
with open(md5file,'w') as fobj:
p.dump(md5dict,fobj)
def incr_backup(src_dir,dst_dir,md5file):
base_dir,back_dir = os.path.split(src_dir.rstrip('/'))
back_name = "%s_incr_%s.tar.gz" % (back_dir,time.strftime("%Y%m%d"))
full_path = os.path.join(dst_dir,back_name)
new_md5 = {}
with open(md5file) as fobj:
old_md5 = p.load(fobj)
for path,dirs,files in os.walk(src_dir):
for each_file in files:
full_name = os.path.join(path,each_file)
new_md5[full_name] = check_md5(full_name)
with open(md5file,'w') as fobj:
p.dump(new_md5,fobj)
os.chdir(base_dir)
tar = tarfile.open(full_path,'w:gz')
for key in new_md5:
#if key not in old_md5 or new_md5[key] != old_md5[key]:
if old_md5.get(key) != new_md5[key]:
#key值是文件名,如果文件名不在老字典中,是新文件;如果value不一样,是改动的文件
tar.add(key.split(base_dir)[1].lstrip('/'))
tar.close()
if __name__ == "__main__":
src_dir = '/home/demo'
dst_dir = '/home/dst'
md5file = '/home/dst/md5.data'
if time.strftime('%a') == "Mon":
full_backup(src_dir,dst_dir,md5file)
else:
incr_backup(src_dir,dst_dir,md5file)
step3:执行结果
[root@host-192-168-3-6 test]# cd -
/home
[root@host-192-168-3-6 home]# mkdir dst
[root@host-192-168-3-6 home]# mkdir demo
[root@host-192-168-3-6 home]# cd -
/root/tarena/test
[root@host-192-168-3-6 test]# python backup.py
[root@host-192-168-3-6 test]# cd -
/home
[root@host-192-168-3-6 home]# ls
demo dst
[root@host-192-168-3-6 home]# cd dst/
[root@host-192-168-3-6 dst]# ls
demo_full_20170801.tar.gz md5.data
step4:修改脚本
把
if time.strftime('%a') == "Mon":
改成
if time.strftime('%a') == "Tue":
step5:执行结果
root@host-192-168-3-6 test]# python backup.py
[root@host-192-168-3-6 test]# cd -
/home/dst
[root@host-192-168-3-6 dst]# ls
demo_full_20170801.tar.gz demo_incr_20170801.tar.gz md5.data