Python运维-日志记录、FTP、邮件提醒


本章目录如下:

五、日志记录

5.1、日志模块简介

5.2、logging模块的配置与使用

六、搭建FTP服务器与客户端

6.1、FTP服务器模式

6.2、搭建服务器

6.3、编写FTP客户端程序

七、邮件提醒

7.1、发送邮件

7.2、接收邮件

7.3、实例:将报警信息实时发送至邮箱


五、日志记录

通过Python的标准库logging模块定制自己多样化的记录日志需求

5.1、日志模块简介

日志模块的第一个例子:简单将日志打印到屏幕:

 import logging
 logging.debug('debug message')
 logging.info('info message')
 logging.warning('warning message')
 logging.error('error message')
 logging.critical('critical message')

默认只显示大于等于WARNING级别的日志,日志级别等级:CRITICAL>ERROR>WARNING>INFO>DEBUG。默认的日志格式:日志级别为Logger,名称为用户输出消息。

各日志级别代表的含义:

  • DEBUG调试时的信息打印
  • INFO正常的日志信息记录
  • WARNING:发生了警告信息,但程序仍能正常工作
  • ERROR:发生了错误,部分功能已不正常
  • CRITICAL:发生严重错误,程序可能已崩溃

第二个例子:将日志信息记录至文件:

 import logging
 logging.basicConfig(filename='./lx_log1.log')
 logging.debug('debug message')
 logging.info('info message')
 logging.warning('warning message')
 logging.error('error message')
 logging.critical('critical message')
 ​
 # 默认的写log文件的方式是追加

5.2、logging模块的配置与使用

5.2.1、logging模块

通过logging模块的配置改变log文件的写入方式、日志级别、时间戳等信息。例:

 logging.basicConfig(level=logging.DEBUG,
                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                     # 日志的格式
                     datefmt="%Y-%m-%d %H:%M:S",     # 时间格式 
                     filename='./lx_log1.log',       # 指定文件位置
                     filemode='w')                   # 指定写入方式

可在logging.basicConfig()函数中通过具体参数来更改logging模块的默认行为:

参数行为
filename用指定的文件名创建FileHandler,这样日志会被存储在指定的文件中
filemode文件打开方式,在指定了filename时用这个参数,默认为a(追加)
format指定handler使用的日志显示格式
datefmt指定日期时间格式
level设置rootlogger的日志级别
stream用指定的stream创建StreamHandler。

format参数中可能用到的格式化串:

参数功能
%(name)sLogger的名字
%(levelno)s数字形式的日志级别
%(levelname)s文本形式的日志级别
%(pathname)s调用日志输出函数的模块的完整路径名,可能没有
%(filename)s调用日志输出函数的模块的文件名
%(module)s调用日志输出函数的模块名
%(funcName)s调用日志输出函数的函数名
%(lineno)d调用日志输出函数的语句所在代码行
%(created)f当前时间,用UNIX标准表示时间的浮点数
%(relativeCreated)d输出日志信息时,自Logger创建以来的毫秒数
%(asctime)s字符串形式的当期时间
%(thread)d线程ID,可能没有
%(threadName)s线程名,可能没有
%(process)d进程ID,可能没有
%(message)s用户输出的消息

实例:

import logging
 logging.basicConfig(
     level=logging.DEBUG,
     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
     # 日志的格式
     datefmt="%Y-%m-%d %H:%M:S",     # 时间格式
     filename='./lx_log1.log',       # 指定文件位置
     filemode='w')                   # 指定写入方式
 logging.debug('debug message')
 logging.info('info message')
 logging.warning('warning message')
 logging.error('error message')
 logging.critical('critical message')

5.2.2、四个器

  • logger记录器,应用程序代码能直接使用的接口
  • handler处理器,将(记录器产生的)日志记录发送至合适的目的地
  • filter过滤器,提供了更好的粒度控制,可以决定输出哪些日志记录
  • formatter格式化器,指明了最终输出中日志记录的布局

日志时间信息在记录器、处理器、过滤器、格式化器之间通过一个日志记录实例来传递。通过调用记录器实例的方法来记录日志,每一个记录器实例都有一个名字,名字相当于命名空间,是一个树状结构。

例如,一个记录器叫scan,记录器scan,tex、scan.html、scan.pdf的父节点。比较好的是:

 logger = logging.getLogger(__name__)

logger和handler的工作流程

实例:将日志信息显示在终端的同时也在文件中记录

 import logging
 ​
 def my_logger(log_file):
     # 实例化记录器,__name__:获取当前文件的名称,名称为任意,也可为空
     logger = logging.getLogger(__name__)
     print(logger.name)      # 打印logger的名称
     logger.setLevel(logging.INFO)   # 设置logger的日志级别为DEBUG,以便记录所有级别的日志
 ​
     # 创建两个处理器,一个负责将日志输出到终端,一个负责输出到文件,并分别设置它们的日志级别
     ch = logging.StreamHandler()    # 终端(控制台)
     ch.setLevel(logging.DEBUG)
     fh = logging.FileHandler(filename=log_file,mode="a",encoding="utf-8")   # 文件
     fh.setLevel(logging.WARNING)
 ​
     # 创建一个格式化器,可以创建不同的格式化器用于不同的handler,这里我们使用一个
     formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
 ​
     # 设置两个handler的格式化器
     ch.setFormatter(formatter)
     fh.setFormatter(formatter)
 ​
     # 为logger添加两个handler
     logger.addHandler(ch)
     logger.addHandler(fh)
 ​
 # 在程序中记录日志
 if __name__ == '__main__':
     logger = my_logger("test1.log")
     logger.debug("这是一个debug日志")
     logger.info("这是一个info日志")
     logger.warning("这是一个warning日志")
     logger.error("这是一个error日志")

handler的日志级别logger的日志级别为基础,logger的日志级别为INFO,低于INFO级别的(如DEBUG)不会出现在handler中。handler中的日志级别高于logger,则只显示更高级别的日志信息。如低于或等于logger的日志级别,则显示logger的日志级别及以上信息。

除了StreamHandler(终端处理器)FileHandler(文件处理器)外,还有其他Handler子类(了解):

Handler子类说明
BaseRotatingHandler循环日志处理器的基类,不能被直接实例化,可使用RotatingFileHandler和TimeRotatingFileHandler
RotatingFileHandler将日志文件记录至磁盘文件,可以设置每个日志文件的最大占用空间
TimeRotatingFileHandler将日志文件记录至磁盘文件,按固定的时间间隔来循环记录日志
SocketHandler可以将日志信息发送到TCP/IP套接字
DatagramHandler可以将日志信息发送到UDP套接字
SMTPHandler可以将日志文件发送至邮箱
SysLogHandler系统日志记录器,可以将日志文件发送至UNIX系统日志,也可以是一个远程机器
NTEventLogHandlerWindows系统事件日志处理器,可以将日志文件发送到Windows系统事件日志
MemoryHandler实例向内存中的缓冲区发送消息,只要满足特定条件,缓冲区就会被刷新
HTTPHandler使用GET或POST方法向HTTP服务器发送消息
WatchedFileandlerWatchedFileandler实例监视它们登录到的文件,如果文件发生更改,则使用文件名关闭并重新打开,只适用unix系统
QueueHandlerQueueHandler实例向队列发送消息,比如在队列或多处理模块中实现的消息
NullHandlerNullHandler实例不适用错误信息,库开发人员使用日志记录,但希望避免在库用户未配置日志记录时显示“日志记录器XXX无法找到任何处理程序”信息

日志的配置信息也可以源于配置文件:示例:

 import logging
 import logging.config
 ​
 logging.config.fileConfig('logging.conf')
 ​
 # 创建一个logger
 logger = logging.getLogger('simpleExample')
 ​
 # 日志记录
 logger.debug("debug message")
 logger.info("info message")
 logger.warning('warning message')
 logger.error('error message')
 logger.critical('critical message')

下面是配置文件信息logging.conf:

 [loggers]
 keys=root,simpleExample
 ​
 [handlers]
 keys=consoleHandler
 ​
 [formatters]
 keys=simpleFormatter
 ​
 [logger_root]
 level=DEBUG
 handlers=consoleHandler
 ​
 [logger_simpleExample]
 level=DEBUG
 handlers=consoleHandler
 qualname=simpleExample
 propagate=0
 ​
 [handler_consoleHandler]
 class=StreamHandler
 level=DEBUG
 formatters=simpleFormatter
 args=(sys.stdout,)
 ​
 [formatter_simpleFormatter]
 format = %(asctime)s -%(name)s -%(levelname)s - %(message)s
 datefmt=%Y-%m-%d %H:%M:%S

六、搭建FTP服务器与客户端

6.1、FTP服务器模式

FTP(File Transfer Protocal,文件传输协议)运行在TCP协议上,使用两个端口,即数据端口命令端口,也称控制端口。默认20是数据端口,21是命令端口

FTP有两种传输模式:主动模式被动模式

6.1.1、主动模式

客户端首先从任意的非特殊端口n(大于1023的端口,也就是客户端的命令端口)连接FTP服务的命令端口(21),向服务器发出命令PORT n+1,告诉服务器使用n+1端口作为数据端口进行数据传输,然后在n+1端口监听

服务器收到PORT n+1后向客户端返回一个“ACK”,然后服务器从它自己的数据端口(20)到客户端先前指定的数据端口(n+1)端口的连接,最后客户端向服务器返回一个‘ACK’,过程结束,如图:

6.1.2、被动模式

服务端发起到客户端的连接,为被动模式,又称PASV,当客户端通知服务器处于被动模式才启用。命令连接和数据连接都是由客户端发起。当开启一个FTP连接时,客户端打开任意两个的非特权本地端口(大于1023)。

第一个端口连接服务器的21端口,但与主动方式的FTP不同,客户端不会提交PORT命令并允许服务器来回连接数据端口,而是提交PASV命令。这会使服务器开启一个任意的非特权端口,并发送PORT P命令给客户端,然后客户端发起从本地端口N+1到服务器的端口P的连接用来传送数据,如图:

6.2、搭建服务器

Python使用pyftpdlib模块进行搭建

 pip install pyftpdlib

6.2.1、快速搭建一个简单的FTP服务器

 python -m pyftpdlib -p 21

执行该命令所在的目录下建立一个端口为21的供下载文件的FTP服务器(Linux系统需要root用户才能使用21端口,windows系统可能是乱码,解决方法:

 # 首先找到pyftpdlib来源:
 import pyftpdlib
 print(pyftpdlib.__path__)
 ​
 # 打开filesystems.py文件,找到
 yield line.encode('utf-8',self.cmd_channel.unicode_errors)
 # 将utf-8修改为gbk
 ​
 # 打开handlers.py,找到:
 return bytes.decode('utf-8',self.unicode_errors)
 # 同样修改为 gbk

6.2.2、搭建一个具有访问权限。可配置相关信息的FTP服务器

from pyftpdlib.authorizers import DummyAuthorizer
 from pyftpdlib.handlers import FTPHandler,ThrottledDTPHandler
 from pyftpdlib.servers import FTPServer
 from pyftpdlib.log import LogFormatter
 import logging
 ​
 # 记录日志,默认情况下日志仅输出到屏幕(终端),这里既输出到屏幕又输出到文件,方便日志查看
 logger = logging.getLogger()
 logger.setLevel(logging.INFO)
 ch = logging.StreamHandler()
 fh = logging.FileHandler(filename='myftpserver.log',encoding='utf-8')
 ch.setFormatter(LogFormatter())
 fh.setFormatter(LogFormatter())
 logger.addHandler(ch)
 logger.addHandler(fh)
 ​
 # 实例化虚拟用户,这是FTP验证的首要条件
 authorizer = DummyAuthorizer()
 # 添加用户权限和路径,括号内的参数是(用户名、密码、用户目录、权限),可以为不同的用户添加不同的目录和权限
 authorizer.add_user("user","12345","d:/",perm="elradfmw")
 # 添加匿名用户,只需要路径
 authorizer.add_anonymous("d:/")
 ​
 # 初始化ftp句柄
 handler = FTPHandler
 handler.authorizer = authorizer
 ​
 # 添加被动端口范围
 handler.passive_ports = range(2000,2333)
 ​
 # 下载上传速度设置
 dtp_handler = ThrottledDTPHandler
 dtp_handler.read_limit = 300 * 1024 # 300kb/s
 dtp_handler.write_limit = 300 * 1024 # 300kb/s
 handler.dtp_handler = dtp_handler
 ​
 # 监听ip和端口,linux里需要root用户才能使用21端口
 server = FTPServer(("0.0.0.0",21),handler)
 ​
 # 最大连接数
 server.max_cons = 150
 server.max_cons_per_ip = 15
 ​
 # 开启服务,自带日志打印信息
 server.serve_forever()

该目录下会生成一个myftpserver.log日志文件,windows进入cmd输入ftp [主机IP]登录该FTP服务器并列出目录(dir命令)进行测试。成功!!说明搭建完成,可自行修改用户权限:

读权限说明写权限说明
e改变文件目录a文件上传
l列出文件d删除文件
r从服务器接收文件f文件重命名
m创建文件
w写权限
M文件传输方式

6.3、编写FTP客户端程序

 from ftplib import FTP
 # 登录FTP
 ftp = FTP(host='localhost',user='user',passwd='12345')
 # 设置编码方式,由于在windows系统上,设置编码为gbk
 ftp.encoding='gbk'
 # 切换目录
 ftp.cwd('test')
 # 列出文件夹的内容
 ftp.retrlines('LIST')   # ftp.dir()
 # 下载文件 note.txt
 ftp.retrbinary('RETR note.txt',open('note.txt','wb').write)
 # 上传文件 server.py
 ftp.storbinary('STOR server.py',open('server.py','rb'))
 # 查看目录下的文件详情
 for f in ftp.mlsd(path='/test'):
     print(f)

七、邮件提醒

7.1、发送邮件

目前发送邮件的协议是SMTPSimple Mail Transfer Protocal,简单邮件传输协议),是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。

python内置的smtplib提供了一种很方便的途径发送电子邮件,可以发送纯文本邮件。HTML邮件及带附件的邮件。Python对SMTP支持有smtplib和email两个模块,email负责构造邮件smtplib负责发送邮件

Python创建SMTP对象语法:

 import smtplib
 smtpObj = smtplib.SMTP([host[,port[,local_hostname]]])
 ​
 # 参数说明
 host:SMTP服务器主机,可以指定主机的IP地址或域名,是可选参数
 port:如果提供了host参数,就需要指定SMTP服务器使用的端口号,一般为25
 local_hostname:如果SMTP在本主机上,那么只需要指定服务器地址为localhost即可

Python SMTP对象使用sendmail方法发送邮件,其语法:

 SMTP.sendmail(from_addr,to_addrs,msg[,mail_options,rcpt_options])
 # 参数说明
 from_addr:邮件发送者地址
 to_addrs:字符串列表,邮件发送地址
 msg:发送消息

构造简单的文本邮件:

使用SMTP发送邮件之前,确保所用邮箱的SMTP服务已开启:例如QQ邮箱:

 from email.mime.text import MIMEText
 message = MIMEText('Python 邮件发送测试...','plain','utf-8')
 ​
 # 第一个参数是邮箱正文
 # 第二个参数是MIME的subtype,传入plain,最终的MIME就是'text/plain'
 # 最后一定要用UTF-8编码保证多语言兼容性

7.1.1、一封简单的邮件

示例:发送第一封简单的邮件(可以自行将重要信息放置在配置文件进行读取):

 import smtplib
 from email.mime.text import MIMEText
 ​
 # 第三方SMTP服务
 mail_host = 'smtp.qq.com'  # 设置服务器
 mail_user = '你的邮箱用户名'  # 用户名
 mail_pass = '你的邮箱口令密码'  # 口令
 ​
 # 发件人
 sender = 'XXX@qq.com'
 # 接收者列表
 receivers = ["XXX@qq.com","XXX@qq.com"]
 ​
 # 构造正文
 message = MIMEText("这是正文:邮件正文...","plain","utf-8")
 message["From"] = sender    # 发件人。必须构造
 message["To"] = ";".join(receivers) # 收件人列表,不是必须的
 message["Subject"] = "这是主题:SMTP邮件测试"
 ​
 try:
     smtpObj = smtplib.SMTP()
     smtpObj.connect(mail_host,587)  # 587为QQ邮箱发送的端口号,163邮箱为25
     smtpObj.login(mail_user,mail_pass)
     smtpObj.sendmail(sender,receivers,message.as_string())
     print("发送成功!!")
 except smtplib.SMTPException as e:
     print(f"发送失败,错误原因:{e}")

HTML格式的邮件例子如下:

 # 修改上述正文部分
 message = MIMEText(
     '<html><body><h1>这是正文标题</h1> \
     <p>正文内容 <a href="#">超链接</a>...</p> \
     </body></html>',
    "plain",
    "utf-8")

7.1.2、带图片及附件的邮件

 import smtplib
 from email.mime.text import MIMEText
 from email.mime.multipart import MIMEMultipart
 from email.mime.image import MIMEImage
 from email.header import Header
 ​
 # 第三方SMTP服务
 mail_host = 'smtp.qq.com'  # 设置服务器
 mail_user = '你的邮箱用户名'  # 用户名
 mail_pass = '你的邮箱口令密码'  # 口令
 ​
 # 发件人
 sender = 'XXX@qq.com'
 # 接收者
 receivers = ["XXX@qq.com",""]
 message = MIMEMultipart()
 ​
 message["From"] = sender    # 发件人。必须构造
 message["To"] = ";".join(receivers) # 收件人列表,不是必须的
 message["Subject"] = "这是主题:SMTP邮件测试"
 ​
 # 构造正文
 message.attach(MIMEText(
     '<p>这是正文:图片及附件发送测试</p><p>图片演示</p><p><img src="cid:image1"></p>',
    "html",
    "utf-8"))
 ​
 # 指定图片为当前目录
 fp = open("XXX.jpg","rb")
 msgImage = MIMEImage(fp.read())
 fp.close()
 ​
 # 定义图片ID,在HTML文本中引用
 msgImage.add_header("Content-ID","<image1>")
 message.attach(msgImage)
 ​
 # 添加附件1,当前目录下的simple.log
 att1 = MIMEText(open("simple.log","rb").read(),"base64","utf-8")
 att1["Content-Type"] = "application/octet-stream"
 # 这里的filename可以随便写,写什么名字,邮件中就显示什么名字
 att1["Content-Disposition"] = 'attachment;filename="simple.log"'    # 法1
 message.attach(att1)
 ​
 # 添加附件2,当前目录下的test.txt
 att2 = MIMEText(open("test.txt","rb").read(),"base64","utf-8")
 att2["Content-Type"] = "application/octet-stream"
 # 这里的filename可以随便写,写什么名字,邮件中就显示什么名字
 att2.add_header("Content-Disposition","attachment",filename=("gbk","","测试.txt"))    # 法2
 message.attach(att2)
 ​
 try:
     smtpObj = smtplib.SMTP()
     smtpObj.connect(mail_host,587)
     smtpObj.login(mail_user,mail_pass)
     smtpObj.sendmail(sender,receivers,message.as_string())
     print("发送成功!!")
 except smtplib.SMTPException as e:
     print(f"发送失败,错误原因:{e}")

7.2、接收邮件

接收邮件的协议有POP3(Post Office Protocal)和IMAP(Internet Message Access Protocal),Python内置poplib模块实现了POP3协议。

收取邮件分以下两步:

  • 用poplib模块把邮件的原始文本下载到本地
  • 用email模块解析原始文本,还原为邮件对象

示例:

 import poplib
 from email.parser import Parser
 from email.header import decode_header
 from email.utils import parseaddr
 ​
 # 输入邮件地址、口令和POP3服务器地址
 email = "邮件地址"
 password = "口令"
 pop3_server = "pop.qq.com"
 ​
 # 连接到POP3服务器,如果开启ss1,就使用poplib.POP3_SSL
 server = poplib.POP3_SSL(pop3_server)
 # 可以打开或关闭调试信息
 server.set_debuglevel(1)
 # 可选:打印POP3服务器的欢迎文字
 print(server.getwelcome().decode("utf-8"))
 ​
 # 身份认证
 server.user(email)
 server.pass_(password)
 ​
 # stat()返回邮件数量和占用空间
 print("邮件数量:%s个。大小:%.2fMB" % (server.stat()[0],server.stat()[1] / 1024 / 1024))
 ​
 # list()返回所有邮件的编号
 resp, mails, octets = server.list()
 # 可以查看返回的列表,类似[b'1 8293',b'2 2184',...]
 ​
 # 获取最新一封邮件,注意索引号从1开始,最新的邮件索引即为邮件的总个数
 index = len(mails)
 resp, lines, octets = server.retr(index)
 ​
 # lines存储了邮件的原始文本的每一行可以获得整个邮件的原始文本
 msg_content = b"\r\n".join(lines).decode("utf-8")
 # 稍后解析出邮件
 msg = Parser().parsestr(msg_content)
 ​
 def decode_str(s):
     value,charset = decode_header(s)[0]
     if charset:
         value = value.decode(charset)
     return value
 def print_address(address_header):
     name, addr = parseaddr(decode_str(address_header))
     print(f"{name} <{addr}>")
 ​
 print("解析获取到的邮件内容如下:\n-------------------begin-----------------")
 # 打印发件人信息
 print_address(msg.get('From', ''))
 # 打印收件人信息
 print_address(msg.get('To', ''))
 # 打印主题信息
 print(decode_str(msg["Subject"]))
 # 打印第一条正文信息
 if msg.is_multipart():
     part0 = msg.get_payload(0)
     content = part0.get_payload(decode=True)
     print(content.decode(part0.get_content_charset()) if part0.get_content_charset() else content.decode())
 else:
     print(msg.get_payload(decode=True).decode(msg.get_content_charset()) if msg.get_content_charset() else msg.get_payload(decode=True))
 ​
 print("------------------end------------------")
 ​
 server.quit()

7.3、实例:将报警信息实时发送至邮箱

相比短信报警,邮件报警是一个非常低成本的解决办法。

报警信息实时发送至邮箱,需求说明如下:

  • 文本文件txt约定格式:第一行为收件人,以逗号分隔;第二行为主题,第三行至最后一行为正文内容,最后一行若是文件,则以附件发送,支持多个附件,以逗号分隔:例如

     xxx@163.com,yyy@163.com 
     xxx程序报警
     ... 
     /home/log/xxx.log,/tmp/yyy/log
  • 持续监控目录A下的txt文件,如果有新增或修改,则读取文本中的内容并发送邮件

  • 有报警需求的程序可生成第一点中格式的文本文件并传送至目录A即可

涉及Python知识点:文件编码、读文件操作、watchdog模块应用及邮件发送

相关代码已上传资源中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/599964.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【系统架构师】-选择题(十四)

1、某企业开发信息管理系统平台进行 E-R 图设计&#xff0c;人力部门定义的是员工实体具有属性&#xff1a;员工号、姓名、性别、出生日期、联系方式和部门,培训部门定义的培训师实体具有属性:培训师号&#xff0c;姓名和职称&#xff0c;其中职称{初级培训师&#xff0c;中级培…

【每日刷题】Day33

【每日刷题】Day33 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 2. 445. 两数相加 II - 力扣&#xff08;…

pytest教程-38-钩子函数-pytest_runtest_protocol

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了pytest_collection_finish钩子函数的使用方法&#xff0c;本小节我们讲解一下pytest_runtest_protocol钩子函数的使用方法。 pytest_runtest_protocol 钩子函数在 pytest 运行单个测试用例之前…

uniapp picker组件的样式更改

不知道有没有小伙伴遇到过这个问题 我是各种穿透和层级都尝试了更改不了其样式 梳理一下 H5端 在全局app.vue下添加如下代码 .uni-picker-container .uni-picker-header{ background-color: $uni-color-pink; //picker头部背景色}.uni-picker-container .…

【busybox记录】【shell指令】uniq

目录 内容来源&#xff1a; 【GUN】【uniq】指令介绍 【busybox】【uniq】指令介绍 【linux】【uniq】指令介绍 使用示例&#xff1a; 去除重复行 - 默认输出 去除重复行 - 跳过第n段&#xff08;空格隔开&#xff09;&#xff0c;比较n1以后的内容&#xff0c;去重 去…

数组折半法查找数据(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> //定义数据&#xff1b; #define N 15int main() {//初始化变量值&#xff1b;int a[N], i, top, bott, loca, flag 1, sign, numb…

使用macof发起MAC地址泛洪攻击

使用macof发起MAC地址泛洪攻击 MAC地址泛洪攻击原理&#xff1a; MAC地址泛洪攻击是一种针对交换机的攻击方式&#xff0c;目的是监听同一局域网中用户的通信数据。交换机的工作核心&#xff1a;端口- MAC地址映射表。这张表记录了交换机每个端口和与之相连的主机MAC地址之间…

Map集合的实现类~HashMap

存储结构&#xff1a;哈希表 键重复依据是hashCode和equals方法&#xff08;键不能重复&#xff09; 添加&#xff1a; 先创建Student类&#xff0c;那么往HashSet添加的就是Student对象作为键值&#xff0c;后面的作为值 删除&#xff1a; 判断&#xff1a; 遍历&#xff1a…

Parts2Whole革新:多参照图定制人像,创新自定义肖像生成框架!

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; Parts2Whole革新&#xff1a;多参照图定制人像&#xff0c;创新自定义肖像生成框架&#xff01; 引言&#xff1a;探索多条件人像生成的新篇章 在数字内容创作…

【MATLAB源码-第204期】基于matlab的语音降噪算法对比仿真,谱减法、维纳滤波法、自适应滤波法;参数可调。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 语音降噪技术的目的是改善语音信号的质量&#xff0c;通过减少或消除背景噪声&#xff0c;使得语音更清晰&#xff0c;便于听者理解或进一步的语音处理任务&#xff0c;如语音识别和语音通讯。在许多实际应用中&#xff0c;如…

深度学习之基于YOLOv5智慧交通拥挤预警检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 随着城市化进程的加速和人口规模的不断增长&#xff0c;交通拥挤问题日益严重。传统的交通拥挤预警方…

C++笔记-makefile添加第三方.h和.cpp及添加.h和lib库模板

目文件结构如下所示时&#xff1a; project/├── main.cpp├── test.cpp├── DIRA/│ ├── A.cpp│ └── A.h├── DIRBLIB/│ └── libB.so└── include/└── B.h Makefile如下所示&#xff1a; # 编译器设置 CXX g CXXFLAGS -stdc11 -Wall# 目录…

互联网十万个为什么之什么是云计算

云计算是一种通过互联网提供计算资源和服务的技术。它允许用户随时随地访问和使用云平台上的数据、软件和硬件资源。在数字化时代&#xff0c;互联网已经成为基础设施。云计算使得数据中心能够像一台计算机一样去工作。通过互联网将算力以按需使用、按量付费的形式提供给用户&a…

2024年Q1脱毛膏线上市场(京东天猫淘宝)销量销额排行榜

鲸参谋监测的2024年Q1季度线上电商平台&#xff08;天猫淘宝京东&#xff09;脱毛膏行业销售数据已出炉&#xff01; 根据鲸参谋数据显示&#xff0c;今年Q1季度在线上电商平台&#xff08;天猫淘宝京东&#xff09;&#xff0c;脱毛膏的销量累计接近220万件&#xff0c;环比增…

基于51单片机的ADC0804的电压表设计(仿真+源码+设计资料)

目录 1、前言 2、资料内容 3、仿真图 4、程序 资料下载地址&#xff1a;基于51单片机的ADC0804的电压表设计&#xff08;仿真源码设计资料&#xff09; 1、前言 最近看网上有很少的ADC0804的设计了&#xff0c;都由0809代替&#xff0c;但是有个别因为成本原因和学校课…

使用Express+Node.js搭建网站

Express是一个基于Node.js平台的快速、开放、极简的Web开发框架。它的作用是专门用来创建Web服务器&#xff0c;与Node.js内置的http模块功能相似&#xff0c;但更为简便和高效。 Express中文官网&#xff1a;Express - 基于 Node.js 平台的 web 应用开发框架 - Express中文文…

25考研英语长难句Day02

25考研英语长难句Day02 【a.词组】【b.断句】 如果你是你讲话对象中的一员&#xff0c;你就能了解你们大家共同的经历和问题&#xff0c;你也可以顺便评论一下食堂里难吃的食物或董事长臭名昭著的领带品味。 【a.词组】 单词解释addressv. 演说&#xff0c; 演讲&#xff1b;…

一堆自定义C#代码片段,让你开发效率飞涨

SharpBoxes 是一款用于 Visual Studio 的扩展&#xff0c;作者为本人&#xff1b; 该扩展旨在提高开发效率。它为开发人员提供了一组日常使用频率较高的代码片段&#xff0c;让你在编写代码时能够更快地插入常用的代码段。通过安装这个扩展&#xff0c;你可以使用快捷键轻松插…

Django 4.x 智能分页get_elided_page_range

Django智能分页 分页效果 第1页的效果 第10页的效果 带输入框的效果 主要函数 # 参数解释 # number: 当前页码&#xff0c;默认&#xff1a;1 # on_each_side&#xff1a;当前页码前后显示几页&#xff0c;默认&#xff1a;3 # on_ends&#xff1a;首尾固定显示几页&#…

【在线OJ】Vue创建OJ管理系统

一、创建项目 vue ui命令创建项目 项目创建完成后来到项目 二、导航栏 首先创建一个根页面&#xff0c;让他展示在页面上 创建之后来到路由配置界面 然后安装ElementUI&#xff0c;来到官网找到导航栏 复制代码后粘贴到刚才创建的vue文件里&#xff0c;启动项目&#xff…