zoukankan      html  css  js  c++  java
  • 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 系统中,行结束标志为’ ’;在 Windows 系统中,行结束标志为’ ’

    #!/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 + '
    ')
        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
    "
                expect "password:"
                    send "$oldpass
    "
            } "password:" { send "$oldpass
    "}
        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 '33[32;1mEmpty stack.33[0m'
    
        else:
            print '33[32;1mpoped [' + stack.pop() + ']33[0m'
    
    def viewstack(): #定义查看函数
        print '33[32;1m', stack, '33[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 = '	
    v
    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 	"
        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 	'
        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 "33[32;1m%s alread exists!33[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 '33[32;1mlogin successful!33[0m'
            else:
                print '33[32;1mlogin incorrect.33[0m'
        else:
            print '33[32;1mlogin incorrect.33[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 '33[31;1mInvalid option.Try again(n / o / q).33[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('
    
    ') + '
    ')
            
        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='
    '):
        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('
    '),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
    '
    
    >>> with open('myadd.py.txt') as f1:
    ...     f1.readline()
    ... 
    '#!/usr/bin/env python
    '
    >>> 

     实现系统中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('
    
    ') + '
    ')
            
        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 = '
    ')
    
    
    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
    '
    >>> 

     编写 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
    %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 "33[31;1m%s%s33[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 "33[31;1m%s%s33[0m" % (prompt,answer)
             
        
        
    if __name__ == "__main__":
        while True:
            probe()
            
            try:    
                yn = raw_input("Continue(y/n)? ").strip()[0]
            except (KeyboardInterrupt,EOFError):
                print "
    Bye 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 "33[31;1m%s%s33[0m" % (prompt,answer)
             
        
        
    if __name__ == "__main__":
        while True:
            probe()
            
            try:    
                yn = raw_input("Continue(y/n)? ").strip()[0]
            except (KeyboardInterrupt,EOFError):
                print "
    Bye 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:
    %s
    " % (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:
    %s
    " % (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
    ' % (log_time, amount_spend, amount_save, new_balance, comment))
        fd.close()
    
    CMDs = {'s': spendMoney, 'v':saveMoney, 'q':queryInfo}
    
    def main():
        prompt = """33[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
    " % (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 '33[31;1m无效的选择,请重试.33[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
    " % (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
    " % (date,'N/A',amount,balance,comment)
                )
        
    def query_money(wallet,record):
        print  "%-12s%-8s%-8s%-10s%-20s
    " % 
        ('date','spend','save','balance','comment')
        with open(record) as fobj:
            for line in fobj:
                print line,
                
        with open(wallet) as fobj:
            print "New Balance: 
    %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 "
    Bye-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
  • 相关阅读:
    无线桥接(WDS)如何设置?
    Linux内核的整体架构简介
    Efuse--芯片存储
    Linux下编写和加载 .ko 文件(驱动模块文件)
    统计难题
    最少拦截系统
    (比赛)B
    (比赛)A
    F
    K
  • 原文地址:https://www.cnblogs.com/zhongguiyao/p/11048446.html
Copyright © 2011-2022 走看看