抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

[toc]

python 日志处理一

练习

  • 实现ls 命令功能,实现-l、-a和 -all、 -h 选项
  1. 实现显示路径下的文件列表;
  2. -a和 -all显示包含.开头的文件;
  3. -l 详细列表显示;
  4. -h 和 -l 配合,人性化显示文件大小,例如1K、1G、1T等。可以认为1G=1000M;
  5. c 字符;d目录;-普通文件;l软链接;b块设备;s socket文件;p pip文件,即FIFO;
  6. -rw-rw-r— 1 python python 5 Oct 00:07 test4;
  7. mode 硬链接 属主 属组 字节 时间 文件名;
  8. 按照文件名排序输出,可以和ls的顺序不一样,但要求文件名排序;
  9. 要求详细列表显示时,时间可以按照”年-月-日 时:分:秒” 格式显示。

* argparse 模块

一个可执行文件或者脚本可以接收参数;

# ls -l /etc
/etc # 是位置参数
-l # 是短选项

如何把这些参数传递给程序呢 ?
从3.2开始Python提供了参数分析的argparse。

  • 参数分类

位置参数放在哪里,就要对应一个参数位置。例如/etc 就是对应一个参数位置;
选项参数,前面必须是通过-的短选项,或者-- 长选项, 然后后面的才算它的参数,当然短选项后面也可以没有参数;

上述中 ‘/etc’ 对应的是位置参数, -l 是选项参数;

基本目录的实现

#!/usr/bin/env python
from pathlib import Path

def showdir(path:str='.'):
    p = Path(path)
    for file in p.iterdir():
        print(file.name)

if __name__ == '__main__':
    showdir('/etc')

基本的解析

先来看一段最简单的程序

#!/usr/bin/env python 
import argparse 
parser = argparse.ArgumentParser() # 获得一个参数解析器
args = parser.parse_args() # 分析参数
parser.help() # 打印帮助

打印结果

usage: if_not.py [-h]

optional arguments:
  -h, --help  show this help message and exit

argparse 不仅仅做了参数的定义和解析,还自动帮助生成了帮助信息。尤其是usage,可以看到定义参数是否是自己想要的;

解析器的参数

prog 程序的名字,缺省使用sys.argv[0]
add_help 自动解析增加-h 和—help 的选项,默认为True
description 为程序功能添加描述
parser = argparse.ArgumentParser(prog='ls',add_help=True,description='list directory contents')

位置参数解析

ls 基本功能应该解决目录内容的打印;
打印的时候应该指定目录的路径,需要位置参数

import argparse 
# 获得一个参数解析器
parser - argparse.ArgumentParser(prog='ls',add_help=True,description='list direct ory contents')
parser.add_argument('path')

args = parser.parse_args() # 分析参数 
parser.print_help() # 打印帮助

程序等定义为:
ls [-h] path
-h为帮助,可有可无
path 为位置参数,必须提供

传参
parse_args(args=None, naespace=None)
args参数列表,一个可迭代对象,内部会把可迭代对象转换成list。如果为None 则使用命令行传入参数,非None则使用args参数的可迭代对象

非必须位置参数

import argparse 
# 获得一个参数解析器
parser = argparse.ArgumentParser(prog='ls',add_help=True, description='list directory  contents')
parser.add_argument('path') #位置参数

args = parser.parse_args(('/etc',)) # 分析参数,同时传入可迭代的参数
print(args) # 打印名词空间中收集的参数
parser.print_help() #打印帮助

运行结果
Namespace(path='/etc')
usage: ls [-h] path

list directory contents

positional arguents
  path

optional arguments
  -h, --help  show this help message and exit
ls: error: the following arguments are required: path

但有时候,ls命令不输入任何路径的话就表示列出当前目录的文件列表。

#!/usr/bin/env python
from pathlib import Path
import argparse
def showdir(path:str='.'):
    p = Path(path)
    for file in p.iterdir():
        print(file.name)
parser = argparse.ArgumentParser(prog='ls', add_help=False, description='list all files') # 构建解析器
parser.add_argument('path', nargs='?',default='.',help='path help') # 位置参数
parser.add_argument('-l',action='store_true')
parser.add_argument('-h',action='store_true')
parser.add_argument('-a','--all',action='store_true')

if __name__ == '__main__':
    args = parser.parse_args(('/etc','-l'))
    parser.print_help()
    print('args=', args)
    print(args.path, args.l, args.h, args.all)

实现

#!/usr/bin/env python
from pathlib import Path
import datetime
import stat

def convert_mode(mode:int):
    modelist = ['r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x']
    modestr = bin(mode)[-9:] # '664' # 110110100
    ret = ""
    for i,c in enumerate(modestr):
        if c == '1':
            ret += modelist[i]
        else:
            ret += '-'
    return ret

# d - s p l c b
def convert_type(file:Path):
    ret =""
    if file.is_symlink():
        ret = 'l'
    elif file.is_fifo():
        ret = 'p'
    elif file.is_socket():
        ret = 's'
    elif file.is_char_device():
        ret = 'c'
    elif file.is_block_device():
        ret = 'b'
    elif file.is_dir():
        ret = 'd'
    else:
        ret = '-'
    return  ret

import argparse
def showdir(path,all=False, detail=False, human=False):
    p = Path(path)
    for file in p.iterdir():
        if not all and str(file.name).startswith('.'): # .开头不打印 --all
            continue
        if detail:
            st = file.stat()
            ## 使用自建convert_mode 函数
            # yield (convert_type(file) + convert_mode(st.st_mode), st.st_nlink, st.st_uid, st.st_gid, st.st_size,
            #        datetime.datetime.fromtimestamp(st.st_atime).strftime('%Y-%m-%d %H:%M:%S'),
            #        file.name)
            ## 使用 stat.filemode 函数
            yield (convert_type(file) + stat.filemode(st.st_mode), st.st_nlink, st.st_uid, st.st_gid, st.st_size,
                   datetime.datetime.fromtimestamp(st.st_atime).strftime('%Y-%m-%d %H:%M:%S'),
                   file.name)
        else:
            yield file.name
parser = argparse.ArgumentParser(prog='ls', add_help=False, description='list all files') # 构建解析器
parser.add_argument('path', nargs='?',default='.',help='path help') # 位置参数
parser.add_argument('-l',action='store_true')
parser.add_argument('-h',action='store_true')
parser.add_argument('-a','--all',action='store_true')

if __name__ == '__main__':
    args = parser.parse_args(('/etc','-l'))
    parser.print_help()
    print('args=', args)
    # print(args.path, args.l, args.h, args.all)
    showdir(args.path)
    for st in showdir(args.path,args.all, args.l, args.h):
        print(st)

优化

#!/usr/bin/env python
from pathlib import Path
import argparse
import datetime
import stat

def listdir(path='.', all=False, detail=False, human=False):
    def _get_human(size :int):
        units = ['B', 'K', 'M', 'G', 'T', 'P']
        depth = 0
        while size >= 1000:
            size = size // 1000
            depth += 1
        return "{} {}".format(size, units[depth])

    def _showdir(path='.', all=False, detail=False, human=False):
        p = Path(path)
        for file in p.iterdir():
            if not all and str(file.name).startswith('.'): # .开头 不打印 --all
                continue
            # -l
            if detail:
                st = file.stat()
                # -rw-rw-r-- 1 python python 2920 Sep 21 07:30 ips
                h = str(st.st_size)
                if human:
                    h = _get_human(st.st_size)
                yield  (stat.filemode(st.st_mode), st.st_nlink, st.st_uid, st.st_gid, h,
                        datetime.datetime.fromtimestamp(st.st_atime).strftime('%Y-%m-%d %H:%M:%S'),file.name)
            else: # 没有 -l
                yield(file.name)
    yield from sorted(_showdir(args.path, args.all, args.l ,args.h ), key=lambda  x: x[len(x) -1])

    # ls [path] [-l] [-a] [-h]
parser = argparse.ArgumentParser(prog='ls', add_help=False, description='list all files')  #构造解析器
parser.add_argument('path',nargs='?',default='.',help='path help') # 位置参数
parser.add_argument('-l',action='store_true')
parser.add_argument('-h',action='store_true')
parser.add_argument('-a','--all',action='store_true')

if __name__ == '__main__':
    args = parser.parse_args()
    parser.print_help()
    print('args=', args)
    for st in listdir(args.path,args.all, args.l ,args.h ):
        print(st)
import argparse
from pathlib import Path
from datetime import datetime
import stat

# 获得一个参数解析器
parser = argparse.ArgumentParser(prog='ls', add_help=False, description='list directory contents')
parser.add_argument('path', nargs='?', default='.', help="directory")  # 位置 参数,可有可无,缺省值,帮助
parser.add_argument('-l', action='store_true', dest='long', help='use a long listing format')
parser.add_argument('-a', '--all', action='store_true', help='show all files, do not ignore entries starting with .')
parser.add_argument('-r', '--reverse', action='store_true', help="reverse order while sorting")
parser.add_argument('-h', '--human-readable', action='store_true', dest='human', help='with -l, print sizes in human readable format')

def _gethuman(size: int):
    units = " KMGTP"
    depth = 0
    while size > 1000 and depth < len(units) - 1:
        # 当前size大于1000,且depth不是最后一个进入循环 depth += 1
        size //= 1000
        depth += 1
    return "{}{}".format(size, units[depth] if depth else '')

def _listdir(path, all, detail, reverse, human):
    p = Path(path)
    for i in p.iterdir():
        if not all and i.name.startswith('.'):  # 不显示隐藏文件
            continue

        if not detail:
            yield (i.name,)
        else:
            # -rw-rw-r-- 1 python python
            # mode 硬链接 属主 属组
            st = i.stat()
            mode = stat.filemode(st.st_mode)
            mtime = datetime.fromtimestamp(st.st_atime).strftime('%Y/%m/%d %H:%M:%S')
            size = st.st_size if not human else _gethuman(st.st_size)
            yield (mode, st.st_nlink, st.st_uid, st.st_gid, size, mtime, i.name)

def listdir(path, all=False, detail=False, reverse=False, human=False):
    """详细列出本目录"""
    return sorted(_listdir(path, all, detail, reverse, human), key=lambda x: x[len(x) - 1], reverse=reverse)

if __name__ == '__main__':
    # args = parser.parse_args('-lrha'.split())  # 分析参数,同时传入可迭代的参数
    args = parser.parse_args()
    print(args)  # 打印名词空间中收集的参数
    parser.print_help()  # 打印帮助
    files = listdir(args.path, args.all, args.long, args.reverse, args.human)
    print(*files, sep='\n')

评论