利用Python实现Linux的ls命令 -l -h -a选项
# coding: utf8import os
import time
import argparse
import datetime
from pathlib import Path
from sys import (stdout, stderr)
from functools import wraps
"""
import stat
stat.file_mode(mode:int)
获取文件权限,直接转换为字符 'rwxrwxrwx'
"""
def catch(func):
@wraps(func)
def _catch(*args, **kwargs):
try:
result = func(*args, **kwargs)
except Exception as err:
stderr.write(str(err) + '\n')
exit(3)
else:
return result
return _catch
def get_args():
"""
获取命令行参数
:return: args object
"""
parser = argparse.ArgumentParser(add_help=False, prog='ls', description='显示目录或文件')
# prog 程序名称
# add_help 是否为其添加一个 -h --help
parser.add_argument('-h', dest='human', help='使文件大小易读', action='store_true')
parser.add_argument('-l', '--list', help='显示详细信息', action='store_true')
parser.add_argument('-a', '--all', help='显示隐藏文件', action='store_true')
parser.add_argument('path', nargs='*', default='.', type=str, help='文件或者目录路径,默认是当前目录')
# nargs? 可有可无 ,没有需要default
# nargs* 多个参数保存为一个列表
# nargs+ 至少一个
# 默认路径,路径可以指定多个
# parser.add_argument('args', nargs=argparse.REMAINDER)
# 将剩余选选项聚集到一个列表, 这个列表将被抛弃。都是无用参数
parser.add_argument('--help', action='help')
# 帮助
return parser.parse_args()
def get_files(path_obj: Path, hide: bool = False):
"""
文件名生成器
:param path_obj: Path object
:param hide: 是否添加隐藏文件
:return:
"""
# if hide:
# yield '.'
# yield '..'
# # 如果需要显示隐藏文件
for file in path_obj.iterdir():
if not hide and file.name.startswith('.'):
# 如果hide为False,文件开头包含'.' 直接跳过
continue
yield file.name
def file_size(size):
"""
文件大小转换为易读数值
:param size: int 原始值
:return: str
"""
# 考虑为深度问题
units = ['', 'K', 'M', 'G', 'T', 'P']
depth = 0
while size >= 1024:
size = round(size / 1024, 1)
depth += 1
return '{}{}'.format(size, units)
def file_type(path_obj):
ret = ''
if path_obj.is_file():
ret = '-'
elif path_obj.is_dir():
ret = 'd'
elif path_obj.is_char_device():
ret = 'c'
elif path_obj.is_fifo():
ret = 'p'
elif path_obj.is_block_device():
ret = 'b'
elif path_obj.is_socket():
ret = 's'
elif path_obj.is_symlink():
ret = 'l'
return ret
def get_mode(n):
"""
权限数字转换为字符
:param n: st_mode
:return: bytes
"""
_purview = n & 0o777
_string = ''
# 获取权限
def _transform(number):
"""
数字转换为权限 rwx
:param number: 十进制数据 0-7
:return: bytes
"""
index = 2
result = bytearray()
for s in b'rwx':
result.append(s if (number >> index & 1) else 0x2D)
index -= 1
return result
string = 'rxw'
for i in range(6, -1, -3):
if i == 6:
tmp = _purview >> i
else:
tmp = _purview >> i & 0o7
_string += ''.join( if (tmp >> _ & 1) else 0x2D for _ in range(2, -1, -1)])
return _string
# def get_mode(n):
# """
# 权限数字转换为字符
# :param n: st_mode
# :return: bytes
# """
# _purview = n & 0o777
# mode_list = {0: 'r', 1: 'w', 2: 'x', 3: 'r', 4: 'w', 5: 'x', 6: 'r', 7: 'w', 8: 'x'}
# ret = ''
# for i in range(8, -1, -1):
# if _purview >> i & 1:
# ret += mode_list
# else:
# ret += '-'
def get_mode1(mode: int):
"""
获取权限, 效率优先于get_mode
:param mode:
:return: string
"""
mode_list = ['r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x']
mode_str = bin(mode)[-9:]# 转为二进制,然后字符串
ret = ''
for index, flag in enumerate(mode_str):
if flag == '1':
ret += mode_list
else:
ret += '-'
return ret
def get_user(uid):
"""
获取用户名
:param uid: uid
:return: username
"""
uid = str(uid)
name_file = '/etc/passwd'
if os.name == 'posix' and Path(name_file).exists():
with open(name_file, encoding='utf8') as file:
for line in file.readlines():
if uid in line:
return line.split(':')
return uid
def get_group(gid):
"""
获取用户组
:param gid: gid
:return: group name
"""
gid = str(gid)
group_file = '/etc/group'
if os.name == 'posix' and Path(group_file).exists():
with open(group_file, encoding='utf8') as file:
for line in file.readlines():
if gid in line:
return line.split(':')
return gid
def detailed(path_obj, size=False):
"""
详细显示文件信息
:param path_obj: 路径对象
:param size: 是否使文件大小易读
:return: string
"""
stat = path_obj.stat()
string = [
# file_type(path_obj).decode() + get_mode(stat.st_mode),# 文件类型和权限
file_type(path_obj) + get_mode1(stat.st_mode),# 文件类型和权限
str(stat.st_nlink),# 硬链接
get_user(stat.st_uid),# uid or user name
# path_obj.owner(),# linux 支持的用户名获取
# path_obj.group(),# linux 支持的用户名获取
get_group(stat.st_gid),# gid or group name
file_size(stat.st_size) if size else str(stat.st_size),# 文件大小
# get_time(stat.st_ctime).decode(),# 创建时间
time.strftime("%Y-%m-%d %H:%M", time.localtime(stat.st_mtime)),# 修改时间
# datetime.datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M'),# 修改时间
path_obj.name if path_obj.name else '.'# 文件名
]
return '\t'.join(string) + '\n'
@catch
def main():
args = get_args()
code = 0
flag = False
for path in args.path:
path_obj = Path(path)
if not path_obj.exists():
# 如果文件不存在
stderr.write('{}: No Such File Or Directory.'.format(path) + '\n')
code = 2
continue
if path_obj.is_dir():
# 如果是个文件夹
if flag:
# 如果之前有文件出现过
stdout.write('\n{}:\n'.format(path_obj.name))
files_list =
files_list.sort(key=str)
if args.list:
# 如果显示了详细信息
for file in files_list:
_path_obj = path_obj / file
# 文件path对象
stdout.write(detailed(_path_obj, args.human))
else:
stdout.write(' '.join(files_list) + '\n')
else:
# 如果不是一个目录
flag = True
if args.list:
# 如果需要显示详细信息
stdout.write(detailed(path_obj, size=args.human))
continue
stdout.write(path_obj.name)
stdout.write('\t')
if flag:
stdout.write('\n')
return code
if __name__ == '__main__':
exit(main())
感谢分享!辛苦辛苦。 谢谢楼主分享 太复杂了,看不太懂! 230行竟然把我@过来了。。
页:
[1]