python解析Linux top 系统信息并生成动态图表(pandas和matplotlib)

文章目录

    • 0. 引言
    • 1. 功能
    • 2.使用步骤
    • 3. 程序架构
        • 流程图
        • 结构图
    • 4. 数据解析模块
    • 5. 图表绘制模块
    • 6. 主程序入口
    • 7. 总结
    • 8. 附录完整代码

0. 引言

在性能调优和系统监控中,top 命令是一种重要工具,提供了实时的系统状态信息,如 CPU 使用率、内存使用情况和进程状态。然而,仅凭命令行输出可能无法满足复杂的分析需求。
本文将介绍如何解析 top 命令的输出,并利用 Python 生成动态图表,以更直观地展示系统性能数据。

1. 功能

  • 解析top 输出

    • 解析top -1 -H -b -n 1800 -d 1获取的进程信息,文本数据通过 pandas 库处理,并使用 matplotlib 生成动态图表。
    • 提取每个进程的 PID、用户、CPU 使用率、内存使用率、运行时间和命令信息。
  • 生成动态图表

    • 绘制系统总体内存使用情况的动态曲线(总内存、空闲内存、使用内存、缓存/缓冲区内存)。
    • 绘制指定进程或线程的 CPU 和内存使用情况的动态曲线。

2.使用步骤

  • dump top文本信息
    • 需要系统统计的设备中,使用如下命令获取top信息top -1 -H -b -n 1800 -d 1 > topdump.txt
      参数 -n 1800 指定了 top 命令执行的次数,即执行1800次。而参数 -d 1 则指定了每次执行之间的时间间隔为1秒,意味着 top 命令每隔1秒就会输出一次进程信息。

    • 注意:dump top信息时,请避免做其他操作以降低干扰。

  • 使用以下命令解析 top 输出文件并生成动态图表:

    python top_parser.py --file topdump.txt --process <process_name> --show_threads --save_fig
    
    • 参数说明:
      • --file:指定 top 输出文件的路径。
      • --process:指定要绘制的进程名称。
      • --show_threads:可选参数,显示进程内所有线程的详细信息。
      • --save_fig:可选参数,保存生成的图表为 PNG 图像文件。
  • 如下图是使用python topparser.py --file topdump.txt --process terminator --save_fig生成的:

python topparser.py --file topdump.txt --process terminator --save_fig生成的

3. 程序架构

本程序主要分为以下几个模块:

  • 数据解析模块:负责解析 top 命令的输出文本,并将提取的数据存储到 pandas 的数据帧中。

  • 图表绘制模块:基于解析得到的数据帧,使用 matplotlib 生成动态图表。

  • 主程序入口:处理命令行参数,调用数据解析模块和图表绘制模块完成数据处理和图表生成的流程。

流程图

流程图将展示数据解析模块、图表绘制模块和主程序入口之间的交互过程。以下是流程图的示意:

主程序入口
解析 `top` 输出文件
生成 `pandas` 数据帧
调用图表绘制模块
生成动态图表
显示或保存图表
结束
结构图

结构图将展示程序的整体架构,包括数据解析模块、图表绘制模块和主程序入口的功能组成及其关系。以下是结构图的示意:

主程序入口
解析 `top` 输出文件
图表绘制模块
处理命令行参数
解析 `top` 输出文本
生成 `pandas` 数据帧
绘制内存使用动态曲线
绘制进程线程动态曲线
时间轴处理
内存使用情况处理
进程线程动态曲线处理
绘制动态图表
存储信息

4. 数据解析模块

数据解析模块的主要任务是读取 top 命令的输出文件,识别其格式并提取出需要的性能指标和进程信息。以下是核心代码片段的部分实现:

# 数据解析模块核心代码示例
import pandas as pd
import re

def parse_top_output(file_path):
    columns = ['timestamp', 'total_mem', 'free_mem', 'used_mem', 'buff_cache_mem', 'pid', 'user', 'cpu', 'mem', 'time', 'command']
    data = {col: [] for col in columns}

    with open(file_path, 'r') as file:
        lines = file.readlines()

    timestamp = None
    format_type = None
    for line in lines:
        if line.startswith('top -'):
            timestamp = re.search(r'top - (\d+:\d+:\d+)', line).group(1)
        elif 'KiB Mem :' in line or 'GiB Mem :' in line:
            format_type = 'format1' if 'KiB Mem :' in line else 'format2'
            mem_info = re.findall(r'[\d\.]+', line)
            if format_type == 'format1':
                data['total_mem'].append(int(mem_info[0]))
                data['free_mem'].append(int(mem_info[1]))
                data['used_mem'].append(int(mem_info[2]))
                data['buff_cache_mem'].append(int(mem_info[3]))
            else:
                total_mem_gb = float(mem_info[0])
                data['total_mem'].append(total_mem_gb * 1024 * 1024)
                data['free_mem'].append(None)
                data['used_mem'].append(None)
                data['buff_cache_mem'].append(None)
            data['timestamp'].append(timestamp)
            data['pid'].append(None)
            data['user'].append(None)
            data['cpu'].append(None)
            data['mem'].append(None)
            data['time'].append(None)
            data['command'].append(None)
        elif re.match(r'\s*\d+', line) or re.match(r'\s*\d+\s+\w+', line):
            if format_type == 'format1':
                proc_info = re.split(r'\s+', line.strip(), maxsplit=11)
                data['pid'].append(int(proc_info[0]))
                data['user'].append(proc_info[1])
                data['cpu'].append(float(proc_info[8]))
                data['mem'].append(float(proc_info[9]))
                data['time'].append(proc_info[10])
                data['command'].append(proc_info[11] if len(proc_info) > 11 else "")
            elif format_type == 'format2':
                proc_info = re.split(r'\s+', line.strip(), maxsplit=10)
                data['pid'].append(int(proc_info[0]))
                data['user'].append(proc_info[1])
                try:
                    cpu_value = float(proc_info[5].strip('%')) if '%' in proc_info[5] else float(proc_info[5])
                    mem_value = float(proc_info[6].strip('%')) if '%' in proc_info[6] else float(proc_info[6])
                except ValueError:
                    cpu_value = 0.0
                    mem_value = 0.0
                data['cpu'].append(cpu_value)
                data['mem'].append(mem_value)
                data['time'].append(proc_info[7])
                data['command'].append(proc_info[9] if len(proc_info) > 9 else "")
            data['timestamp'].append(timestamp)
            data['total_mem'].append(None)
            data['free_mem'].append(None)
            data['used_mem'].append(None)
            data['buff_cache_mem'].append(None)
        else:
            data['timestamp'].append(timestamp)
            for key in data:
                if key not in ['timestamp']:
                    data[key].append(None)

    df = pd.DataFrame(data)
    df['timestamp'] = pd.to_datetime(df['timestamp'], format='%H:%M:%S')
    df['relative_time'] = (df['timestamp'] - df['timestamp'].min()).dt.total_seconds()
    return df

5. 图表绘制模块

图表绘制模块利用 matplotlib 库生成动态图表,以下是绘制内存使用动态曲线和进程线程动态曲线的核心代码片段:

# 图表绘制模块核心代码示例
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator, AutoLocator

def plot_memory_usage(ax, df, process_name=None):
    if 'relative_time' not in df.columns:
        print("relative_time column is missing in the dataframe")
        return
    
    memory_cols = ['total_mem', 'free_mem', 'used_mem', 'buff_cache_mem']
    df_memory = df.dropna(subset=memory_cols).drop_duplicates(subset=['relative_time'])

    max_memory = df_memory[memory_cols].max().max()  # 获取内存使用的最大值

    for col in memory_cols:
        ax.plot(df_memory['relative_time'], df_memory[col], label=col.replace('_', ' ').title())

    ax.set_xlabel('Time (seconds)')
    ax.set_ylabel('Memory (KiB)')
    ax.set_ylim(0, max_memory * 1.1 if max_memory > 0 else 1)
    ax.set_title('Memory Usage Over Time')
    if process_name:
        ax.text(0.5, 0.5, process_name, transform=ax.transAxes, fontsize=20, ha='center', va='center', alpha=0.7, color='black')
    ax.legend()
    ax.grid(True)
    ax.xaxis.set_major_locator(AutoLocator())
    ax.yaxis.set_major_locator(MaxNLocator(integer=True))

    return ax

def plot_process_threads(ax, df, processes, show_threads, metric='cpu'):
    for process in processes:
        df_process = df[df['command'].str.contains(process, na=False)]
        if show_threads:
            unique_pids = df_process['pid'].unique()
            for pid in unique_pids:
                df_pid = df_process[df_process['pid'] == pid]
                ax.plot(df_pid['relative_time'], df_pid[metric], label=f'{process} {metric.upper()} (PID {pid})')
        else:
            df_process_grouped = df_process.groupby('relative_time').agg({metric: 'sum'}).reset_index()
            ax.plot(df_process_grouped['relative_time'], df_process_grouped[metric], label=f'{process} (Total {metric.upper()})')
    ax.set_xlabel('

Time (seconds)')
    ax.set_ylabel(f'{metric.upper()} Usage')
    ax.set_title(f'{metric.upper()} Usage of Processes and Threads Over Time')
    ax.legend()
    ax.grid(True)
    ax.xaxis.set_major_locator(AutoLocator())
    ax.yaxis.set_major_locator(MaxNLocator(integer=True))

    return ax

6. 主程序入口

主程序入口负责处理命令行参数,并调用数据解析和图表绘制模块完成数据处理和图表生成的流程。以下是主程序入口的核心代码片段:

# 主程序入口核心代码示例
import argparse

def main(file_path, processes, show_threads, save_fig=False):
    df = parse_top_output(file_path)
    plot_all(df, processes, show_threads, save_fig)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Parse and plot top command output.')
    parser.add_argument('--file', type=str, required=True, help='Path to the top output file')
    parser.add_argument('--process', type=str, nargs='+', required=True, help='List of processes to plot')
    parser.add_argument('--show_threads', action='store_true', help='Show CPU and memory for all threads within the process')
    parser.add_argument('--save_fig', action='store_true', help='Save the generated plots as PNG images')

    args = parser.parse_args()
    main(args.file, args.process, args.show_threads, args.save_fig)

7. 总结

通过本文介绍的方法,可以有效解析 top 命令输出并生成动态图表,帮助用户更直观地分析系统性能数据。该方法不仅支持不同格式的 top 输出,还能够灵活配置,满足各种监控需求。

8. 附录完整代码

import pandas as pd
import matplotlib.pyplot as plt
import re
import argparse
from matplotlib.ticker import MaxNLocator, AutoLocator

# 解析top命令输出
def parse_top_output(file_path):
    columns = ['timestamp', 'total_mem', 'free_mem', 'used_mem', 'buff_cache_mem', 'pid', 'user', 'cpu', 'mem', 'time', 'command']
    data = {col: [] for col in columns}

    with open(file_path, 'r') as file:
        lines = file.readlines()

    timestamp = None
    format_type = None
    for line in lines:
        if line.startswith('top -'):
            timestamp = re.search(r'top - (\d+:\d+:\d+)', line).group(1)
        elif 'KiB Mem :' in line or 'GiB Mem :' in line:
            format_type = 'format1' if 'KiB Mem :' in line else 'format2'
            mem_info = re.findall(r'[\d\.]+', line)
            if format_type == 'format1':
                data['total_mem'].append(int(mem_info[0]))
                data['free_mem'].append(int(mem_info[1]))
                data['used_mem'].append(int(mem_info[2]))
                data['buff_cache_mem'].append(int(mem_info[3]))
            else:
                total_mem_gb = float(mem_info[0])
                data['total_mem'].append(total_mem_gb * 1024 * 1024)
                data['free_mem'].append(None)
                data['used_mem'].append(None)
                data['buff_cache_mem'].append(None)
            data['timestamp'].append(timestamp)
            data['pid'].append(None)
            data['user'].append(None)
            data['cpu'].append(None)
            data['mem'].append(None)
            data['time'].append(None)
            data['command'].append(None)
        elif re.match(r'\s*\d+', line) or re.match(r'\s*\d+\s+\w+', line):
            if format_type == 'format1':
                proc_info = re.split(r'\s+', line.strip(), maxsplit=11)
                data['pid'].append(int(proc_info[0]))
                data['user'].append(proc_info[1])
                data['cpu'].append(float(proc_info[8]))
                data['mem'].append(float(proc_info[9]))
                data['time'].append(proc_info[10])
                data['command'].append(proc_info[11] if len(proc_info) > 11 else "")
            elif format_type == 'format2':
                proc_info = re.split(r'\s+', line.strip(), maxsplit=10)
                data['pid'].append(int(proc_info[0]))
                data['user'].append(proc_info[1])
                try:
                    cpu_value = float(proc_info[5].strip('%')) if '%' in proc_info[5] else float(proc_info[5])
                    mem_value = float(proc_info[6].strip('%')) if '%' in proc_info[6] else float(proc_info[6])
                except ValueError:
                    cpu_value = 0.0
                    mem_value = 0.0
                data['cpu'].append(cpu_value)
                data['mem'].append(mem_value)
                data['time'].append(proc_info[7])
                data['command'].append(proc_info[9] if len(proc_info) > 9 else "")
            data['timestamp'].append(timestamp)
            data['total_mem'].append(None)
            data['free_mem'].append(None)
            data['used_mem'].append(None)
            data['buff_cache_mem'].append(None)
        else:
            data['timestamp'].append(timestamp)
            for key in data:
                if key not in ['timestamp']:
                    data[key].append(None)

    df = pd.DataFrame(data)
    df['timestamp'] = pd.to_datetime(df['timestamp'], format='%H:%M:%S')
    df['relative_time'] = (df['timestamp'] - df['timestamp'].min()).dt.total_seconds()
    return df

# 将时间戳转换为秒数
def convert_timestamp_to_seconds(timestamp):
    h, m, s = map(int, timestamp.split(':'))
    return h * 3600 + m * 60 + s

# 绘制内存动态曲线
def plot_memory_usage(ax, df, process_name=None):
    if 'relative_time' not in df.columns:
        print("relative_time column is missing in the dataframe")
        return

    memory_cols = ['total_mem', 'free_mem', 'used_mem', 'buff_cache_mem']
    df_memory = df.dropna(subset=memory_cols).drop_duplicates(subset=['relative_time'])

    max_memory = df_memory[memory_cols].max().max()  # 获取内存使用的最大值

    for col in memory_cols:
        ax.plot(df_memory['relative_time'], df_memory[col], label=col.replace('_', ' ').title())

    ax.set_xlabel('Time (seconds)')
    ax.set_ylabel('Memory (KiB)')
    ax.set_ylim(0, max_memory * 1.1 if max_memory > 0 else 1)
    ax.set_title('Memory Usage Over Time')
    if process_name:
        ax.text(0.5, 0.5, process_name, transform=ax.transAxes, fontsize=20, ha='center', va='center', alpha=0.7, color='black')
    ax.legend()
    ax.grid(True)
    ax.xaxis.set_major_locator(AutoLocator())
    ax.yaxis.set_major_locator(MaxNLocator(integer=True))

    return ax

# 绘制进程和线程动态曲线
def plot_process_threads(ax, df, processes, show_threads, metric='cpu'):
    for process in processes:
        df_process = df[df['command'].str.contains(process, na=False)]
        if show_threads:
            unique_pids = df_process['pid'].unique()
            for pid in unique_pids:
                df_pid = df_process[df_process['pid'] == pid]
                ax.plot(df_pid['relative_time'], df_pid[metric], label=f'{process} {metric.upper()} (PID {pid})')
        else:
            df_process_grouped = df_process.groupby('relative_time').agg({metric: 'sum'}).reset_index()
            ax.plot(df_process_grouped['relative_time'], df_process_grouped[metric], label=f'{process} (Total {metric.upper()})')
    ax.set_xlabel('Time (seconds)')
    ax.set_ylabel(f'{metric.upper()} Usage')
    ax.set_title(f'{metric.upper()} Usage of Processes and Threads Over Time')
    ax.legend()
    ax.grid(True)
    ax.xaxis.set_major_locator(AutoLocator())
    ax.yaxis.set_major_locator(MaxNLocator(integer=True))

    return ax

# 绘制图表
def plot_all(df, processes, show_threads, save_fig=False):
    for process in processes:
        fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(12, 12))
        df_process = df[df['command'].str.contains(process, na=False)]
        if show_threads:
            plot_process_threads(axes[0], df_process, [process], show_threads, metric='mem')
            plot_process_threads(axes[1], df_process, [process], show_threads, metric='cpu')
        else:
            plot_memory_usage(axes[0], df, process_name=process)
            plot_process_threads(axes[1], df, [process], show_threads)

        plt.tight_layout(pad=3.0)

        if save_fig:
            fig.savefig(f'{process}_analysis.png')  # 保存图像

        plt.show()

# 主函数
def main(file_path, processes, show_threads, save_fig=False):
    df = parse_top_output(file_path)
    plot_all(df, processes, show_threads, save_fig)

# 处理命令行参数
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Parse and plot top command output.')
    parser.add_argument('--file', type=str, required=True, help='Path to the top output file')
    parser.add_argument('--process', type=str, nargs='+', required=True, help='List of processes to plot')
    parser.add_argument('--show_threads', action='store_true', help='Show CPU and memory for all threads within the process')
    parser.add_argument('--save_fig', action='store_true', help='Save the generated plots as PNG images')

    args = parser.parse_args()
    main(args.file, args.process, args.show_threads, args.save_fig)

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

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

相关文章

我爱服务器——LVM实战学习

后来呀&#xff0c;天亮之前毕业后踏入服务器领域了。。。。。。 LVM&#xff08;Logical Volume Manager&#xff09;是一个高级的磁盘管理框架&#xff0c;它允许用户将多个物理硬盘组合成一个逻辑卷&#xff0c;从而提供更大的存储空间、更高的灵活性和更好的数据管理能力。…

创业新选择:乐财业,让财税事业更简!

在市场需求和国家政策的双重驱动之下&#xff0c;【乐财业智慧财税赋能平台】基于鹦鹉智能财税系统、完善的税务资源供应链&#xff0c;财税专家团等&#xff0c;首创为企业提供“业财税”一体化的一站式财税解决方案&#xff0c;让财税生意更好做。 乐财业通过全国布局线下渠道…

Windows中Git的使用(2024最新版)

Windows中Git的使用 获取ssh keys本地绑定邮箱初始化本地仓库添加到本地缓存区提交到本地缓存区切换本地分支为main关联远程分支推送到GitHub查看推送日志 Git 2020年发布了新的默认分支名称"main"&#xff0c;取代了"master"作为主分支的名称。操作有了些…

MySQL数据库主从复制+mycat读写分离+MHA实操

目录 一、主从复制 1.1 主从复制简介 1.2 MySQL支持的复制类型 1.3 主从复制的工作过程 1.4 主从复制的同步模式 1.4.1 异步复制&#xff08;Asynchronous replication&#xff09; 1.4.2 全同步复制&#xff08;Fully synchronous replication&#xff09; 1.4.3 半同…

React+TS前台项目实战(二十三)-- 基于属性自定义数值显示组件Decimal封装

文章目录 前言Decimal组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示 总结 前言 今天要封装的Decimal 组件&#xff0c;是通过传入的属性进行定制化显示数值&#xff0c;在渲染时&#xff0c;会根据不同的情况显示整数部分、小数部分和单位&#xff0c;支持自定义样式…

Go源码--context包

简介 Context 是go语言比较重要的且也是比较复杂的一个结构体&#xff0c;Context主要有两种功能: 取消信号&#xff1a;包括直接取消&#xff08;涉及的结构体&#xff1a;cancelCtx ; 涉及函数&#xff1a;WithCancel&#xff09;和携带截止日期的取消&#xff08;涉及结构…

【Java安装】windows10+JDK21+IDEA

文章目录 一、JDK安装1. 下载完成后按照自己需要的位置安装2. 配置环境变量2.1 JAVA_HOME变量2.2 PATH配置 3. 验证4. helloworld 二、IDEA安装三、IDEA-HelloWorld 一、JDK安装 JDK安装链接 1. 下载完成后按照自己需要的位置安装 2. 配置环境变量 2.1 JAVA_HOME变量 安装…

JVM原理(三):JVM对象回收判定机制与回收算法

如何判断一个对象是否存活(即是否还分配在堆中)&#xff0c;那看他是否还在用。 1. 引用计数算法 这是一种判断方式&#xff0c;相应的方法就是&#xff1a;如果一个对象被引用&#xff0c;那将被引用的对象中的一个计数器加一&#xff0c;引用失效就减一。在任何时刻引用计数…

QT实现GIF动图显示(小白版,可直接copy使用)

需要你自己提前设置好动图的位置&#xff0c;本例中存放于"/Users/PLA/PLA/PLA.gif widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMovie> #include <QLabel>class Widget : public QWidget {Q_OBJECTpublic:explicit Wid…

mssql查询历史执行过的语句日志

SELECT deqs.creation_time,dest.text AS [SQL Text],deqs.execution_count,deqs.total_elapsed_time,deqs.total_worker_time FROM sys.dm_exec_query_stats AS deqs CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest--where dest.text like %这个是我的条件&#…

基于Springboot的智慧养老中心管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Springboot的智慧养老中心管理系统,…

全景图三维3D模型VR全景上传展示H5开发

全景图三维3D模型VR全景上传展示H5开发 3D互动体验平台的核心功能概览 兼容广泛格式&#xff1a;支持OBJ、FBX、GLTF等主流及前沿3D模型格式的无缝上传与展示&#xff0c;确保创意无界。 动态交互探索&#xff1a;用户可自由旋转、缩放、平移模型&#xff0c;深度挖掘每一处…

默安逐日实验室:XDP的应用实践

1. 网络数据包是如何进入进计算机的 众所周知&#xff0c;网络数据包通常需要在TCP/IP协议栈中进行处理&#xff0c;但网络数据包并不直接进入TCP/IP协议栈&#xff1b;相反&#xff0c;他们直接进入网络接口。因此&#xff0c;在数据包进入 TCP/IP 堆栈之前&#xff0c;它们已…

HTML如何在图片上添加文字

HTML如何在图片上添加文字 当我们开发一个页面&#xff0c;插入图片时&#xff0c;需要有一组文字对图片进行描述。那么HTML中如何在图片上添加文字呢&#xff1f;这篇文章告诉你。 先让我们来看下效果图&#xff1a; 句子“这是一张夜空图片”被放置在了图片的左下角。 那么…

谷粒商城学习-10-docker安装mysql

文章目录 一&#xff0c;拉取MySQL镜像1&#xff0c;搜索MySQL的Docker镜像2&#xff0c;拉取MySQL镜像3&#xff0c;查看已经拉取的镜像 二&#xff0c;创建、启动MySQL容器1&#xff0c;使用docker run创建启动容器2&#xff0c;使用docker ps查看运行状态的容器3&#xff0c…

属性描述符初探——Vue实现数据劫持的基础

目录 属性描述符——Vue实现数据劫持的基础 一、属性描述符是什么&#xff1f; ​编辑 1.1、属性描述符示例 1.2、用属性描述符定义属性及获取对象的属性描述符 1.3、带有读取器和设置器的属性描述符 二、使用属性描述符的情景 2.1、封装和数据隐藏 使用getter和setter…

论文写作全攻略:Kimi辅助下的高效学术写作技巧

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 完成论文写作是一个多阶段的过程&#xff0c;涉及到不同的任务和技能。以下是按不同分类总结的向Kimi提问的prompt&#xff0c;以帮助你在论文写作过程中取得成功&#xff1a; 1. 选题与…

使用kali Linux启动盘轻松破解Windows电脑密码

破解分析文章仅限用于学习和研究目的&#xff1b;不得将上述内容用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。谢谢&#xff01;&#xff01; 效果展示&#xff1a; 使用kali Linux可以轻松破解Windows用户及密码 准备阶段&#xff1a; &#xff08…

RedHat9 | kickstart无人值守批量安装

一、知识补充 kickstart Kickstart是一种用于Linux系统安装的自动化工具&#xff0c;它通过一个名为ks.cfg的配置文件来定义Linux安装过程中的各种参数和设置。 kickstart的工作原理 Kickstart的工作原理是通过记录典型的安装过程中所需人工干预填写的各种参数&#xff0c;…

配置基于用户认证的虚拟主机

添加账号abc [rootlocalhost conf.d]# htpasswd -c /etc/httpd/zhanghao abc New password: Re-type new password: Adding password for user abc添加账号tom [rootlocalhost conf.d]# htpasswd /etc/httpd/zhanghao tom New password: Re-type new password: Adding pa…