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