dsh-linux-commander 0.0.0-stage → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +93 -2
- package/build-client.mjs +59 -0
- package/client.js +427 -0
- package/cordis.patch.yml +12 -0
- package/icon.svg +6 -0
- package/index.js +82 -0
- package/locale/en.json +21 -0
- package/locale/zh.json +21 -0
- package/package.json +41 -3
- package/src/ai.js +186 -0
- package/src/client/widget.js +393 -0
- package/src/commands.js +266 -0
- package/src/core.js +244 -0
- package/src/nl.js +228 -0
package/src/commands.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// Linux 指令器 — 内置指令库(纯数据,无依赖、无副作用)
|
|
2
|
+
// COMMANDS: 指令名 -> { d: 一句话中文解释, f: 常用参数说明, danger: 可选风险提示 }
|
|
3
|
+
// DANGER_RULES: 运行时危险参数模式(re 为正则源码字符串,消费方以 new RegExp(re, 'i') 编译)
|
|
4
|
+
// 说明以 GNU/Linux coreutils 与常见工具为准;f 中同时收录少量常用子命令,便于展示。
|
|
5
|
+
|
|
6
|
+
export const COMMANDS = {
|
|
7
|
+
// ===== 文件与目录 =====
|
|
8
|
+
ls: { d: '列出目录内容', f: { '-l': '长格式显示详细信息', '-a': '包含隐藏文件', '-h': '以可读单位显示大小', '-R': '递归列出子目录', '-t': '按修改时间排序', '-S': '按文件大小排序', '-r': '反转排序结果', '-d': '仅显示目录本身', '--color': '彩色区分文件类型' } },
|
|
9
|
+
cd: { d: '切换当前工作目录', f: { '-P': '进入符号链接指向的物理目录', '-L': '跟随符号链接(默认行为)' } },
|
|
10
|
+
pwd: { d: '显示当前工作目录的绝对路径', f: { '-L': '显示逻辑路径(默认)', '-P': '显示解析符号链接后的物理路径' } },
|
|
11
|
+
mkdir: { d: '创建目录', f: { '-p': '递归创建多级目录且已存在不报错', '-m': '创建时指定权限模式', '-v': '显示创建过程' } },
|
|
12
|
+
rmdir: { d: '删除空目录', f: { '-p': '连同变空的父目录一起删除', '--ignore-fail-on-non-empty': '忽略目录非空的错误' } },
|
|
13
|
+
rm: { d: '删除文件或目录', f: { '-r': '递归删除目录及其内容', '-f': '强制删除不提示', '-i': '删除前逐个确认', '-v': '显示删除过程', '-d': '删除空目录' }, danger: '删除后难以恢复,请确认路径' },
|
|
14
|
+
cp: { d: '复制文件或目录', f: { '-r': '递归复制目录', '-i': '覆盖前询问', '-f': '强制覆盖已存在文件', '-p': '保留权限和时间戳等属性', '-a': '归档模式,保留所有属性', '-u': '仅复制更新的文件', '-v': '显示复制过程' } },
|
|
15
|
+
mv: { d: '移动或重命名文件与目录', f: { '-i': '覆盖前询问', '-f': '强制覆盖不提示', '-u': '仅移动更新的文件', '-n': '不覆盖已存在的文件', '-v': '显示移动过程' } },
|
|
16
|
+
touch: { d: '创建空文件或更新文件时间戳', f: { '-a': '仅修改访问时间', '-m': '仅修改修改时间', '-t': '用指定时间戳设置', '-c': '文件不存在时不创建', '-d': '用日期字符串设置时间' } },
|
|
17
|
+
cat: { d: '连接并输出文件内容', f: { '-n': '对所有行编号', '-b': '仅对非空行编号', '-s': '压缩连续空行为一行', '-A': '显示所有不可见字符', '-E': '在行尾显示 $ 符号' } },
|
|
18
|
+
tac: { d: '按行倒序输出文件内容', f: { '-s': '指定行分隔符' } },
|
|
19
|
+
head: { d: '输出文件开头部分(默认 10 行)', f: { '-n': '指定显示的行数', '-c': '指定显示的字节数', '-q': '不显示文件名标题', '-v': '始终显示文件名标题' } },
|
|
20
|
+
tail: { d: '输出文件末尾部分(默认 10 行)', f: { '-n': '指定显示的行数', '-f': '实时跟踪新增内容', '-F': '按文件名跟踪并自动重试', '-c': '指定显示的字节数', '--pid': '指定进程结束后停止跟踪' } },
|
|
21
|
+
less: { d: '分页查看文件内容,支持前后翻页', f: { '-N': '显示行号', '-S': '长行不换行而左右滚动', '-i': '搜索时忽略大小写', '-R': '正确显示 ANSI 颜色', '-F': '内容不足一屏时直接退出' } },
|
|
22
|
+
more: { d: '分页查看文件内容(只能向下翻)', f: { '-d': '显示操作提示', '-s': '压缩连续空行', '-c': '清屏后从顶部显示' } },
|
|
23
|
+
grep: { d: '按模式搜索文本内容', f: { '-i': '忽略大小写', '-r': '递归搜索目录', '-n': '显示匹配行号', '-v': '反向匹配,输出不匹配的行', '-E': '使用扩展正则表达式', '-F': '按固定字符串匹配', '-w': '全词匹配', '-c': '统计匹配行数', '-l': '只列出包含匹配的文件名', '-o': '只输出匹配到的部分', '-A': '显示匹配行之后的 N 行', '-B': '显示匹配行之前的 N 行', '-C': '显示匹配行前后的 N 行' } },
|
|
24
|
+
egrep: { d: '等价于 grep -E,使用扩展正则搜索', f: { '-i': '忽略大小写', '-n': '显示行号', '-r': '递归搜索目录', '-v': '反向匹配', '-c': '统计匹配行数' } },
|
|
25
|
+
fgrep: { d: '等价于 grep -F,按固定字符串搜索', f: { '-i': '忽略大小写', '-n': '显示行号', '-r': '递归搜索目录', '-v': '反向匹配', '-c': '统计匹配行数' } },
|
|
26
|
+
find: { d: '按条件在目录树中查找文件', f: { '-name': '按文件名匹配(支持通配符)', '-iname': '按文件名匹配且忽略大小写', '-type': '按类型过滤,f 文件 d 目录', '-size': '按文件大小过滤', '-mtime': '按修改天数过滤', '-maxdepth': '限制查找深度', '-exec': '对查找结果执行命令', '-delete': '删除匹配到的文件', '-empty': '查找空文件或空目录', '-user': '按属主过滤' } },
|
|
27
|
+
locate: { d: '基于数据库快速查找文件路径', f: { '-i': '忽略大小写', '-n': '限制返回结果数量', '-r': '使用正则表达式匹配' } },
|
|
28
|
+
which: { d: '显示命令对应的可执行文件路径', f: { '-a': '显示所有匹配的路径' } },
|
|
29
|
+
whereis: { d: '查找命令的程序、源码和手册位置', f: { '-b': '只查找二进制程序', '-m': '只查找手册页', '-s': '只查找源码' } },
|
|
30
|
+
file: { d: '识别文件类型', f: { '-i': '输出 MIME 类型', '-b': '不显示文件名前缀', '-L': '跟随符号链接', '-z': '尝试查看压缩文件内部类型' } },
|
|
31
|
+
stat: { d: '显示文件或文件系统的详细状态', f: { '-c': '按自定义格式输出', '-f': '显示文件系统状态而非文件', '-L': '跟随符号链接' } },
|
|
32
|
+
ln: { d: '创建硬链接或符号链接', f: { '-s': '创建符号链接(软链接)', '-f': '强制覆盖已存在的链接', '-n': '把指向目录的符号链接当普通文件处理', '-v': '显示创建过程' } },
|
|
33
|
+
readlink: { d: '输出符号链接指向的目标或规范路径', f: { '-f': '输出规范化后的绝对路径', '-n': '不输出末尾换行符' } },
|
|
34
|
+
realpath: { d: '输出路径的规范绝对路径', f: { '-s': '不解析符号链接', '-e': '要求路径所有组件必须存在', '--relative-to': '输出相对于指定目录的路径' } },
|
|
35
|
+
basename: { d: '去掉路径前缀,取文件名部分', f: { '-a': '支持处理多个参数', '-s': '同时去掉指定后缀' } },
|
|
36
|
+
dirname: { d: '去掉文件名,取目录部分', f: { '-z': '用 NUL 而非换行分隔输出' } },
|
|
37
|
+
tree: { d: '以树状结构列出目录内容', f: { '-a': '包含隐藏文件', '-d': '只列出目录', '-L': '限制显示的层级深度', '-h': '以可读单位显示大小', '-I': '排除匹配模式的文件' } },
|
|
38
|
+
wc: { d: '统计文件的行数、单词数和字节数', f: { '-l': '只统计行数', '-w': '只统计单词数', '-c': '只统计字节数', '-m': '只统计字符数', '-L': '输出最长行的长度' } },
|
|
39
|
+
sort: { d: '对文本行排序', f: { '-n': '按数值大小排序', '-r': '逆序输出', '-k': '指定排序的列', '-t': '指定列分隔符', '-u': '排序并去除重复行', '-f': '忽略大小写', '-h': '按可读大小单位排序', '-o': '将结果写入指定文件' } },
|
|
40
|
+
uniq: { d: '去除相邻的重复行(常与 sort 连用)', f: { '-c': '在行首统计重复次数', '-d': '只输出重复出现的行', '-u': '只输出不重复的行', '-i': '忽略大小写', '-f': '跳过前 N 个字段再比较' } },
|
|
41
|
+
cut: { d: '按列或字符位置截取文本', f: { '-d': '指定列分隔符', '-f': '选取指定的列', '-c': '按字符位置选取', '-b': '按字节位置选取', '--complement': '反选,输出未选中的部分' } },
|
|
42
|
+
tr: { d: '转换、压缩或删除字符', f: { '-d': '删除指定字符', '-s': '压缩连续重复字符', '-c': '取字符集的补集', '-t': '将第一字符集截断到第二集长度' } },
|
|
43
|
+
tee: { d: '把标准输入同时输出到屏幕和文件', f: { '-a': '追加到文件而非覆盖', '-i': '忽略中断信号' } },
|
|
44
|
+
xargs: { d: '把标准输入转换为命令参数执行', f: { '-n': '每次最多传递 N 个参数', '-I': '指定替换占位符', '-0': '以 NUL 分隔输入项', '-P': '并行运行的进程数', '-t': '执行前先打印命令', '-p': '执行前询问确认' } },
|
|
45
|
+
sed: { d: '流编辑器,按行替换和处理文本', f: { '-n': '静默模式,只打印指定行', '-i': '直接修改原文件', '-e': '追加一条编辑脚本', '-E': '使用扩展正则表达式', '-r': '同 -E 的旧写法' } },
|
|
46
|
+
awk: { d: '按列处理文本的编程语言', f: { '-F': '指定字段分隔符', '-v': '定义变量并赋值', '-f': '从文件读取程序脚本' } },
|
|
47
|
+
diff: { d: '逐行比较文件差异', f: { '-u': '以统一格式输出差异', '-r': '递归比较目录', '-q': '只报告文件是否不同', '-i': '忽略大小写', '-w': '忽略空白差异', '--color': '彩色高亮差异' } },
|
|
48
|
+
comm: { d: '逐行比较两个已排序文件的异同', f: { '-1': '不输出第 1 列(文件1独有)', '-2': '不输出第 2 列(文件2独有)', '-3': '不输出第 3 列(两者共有)' } },
|
|
49
|
+
paste: { d: '按列合并多个文件的对应行', f: { '-d': '指定列分隔符', '-s': '把每个文件串行合并为一行' } },
|
|
50
|
+
split: { d: '把大文件切分成多个小文件', f: { '-l': '按行数切分', '-b': '按大小切分', '-n': '切分成 N 份', '-d': '使用数字后缀' } },
|
|
51
|
+
join: { d: '按公共列连接两个已排序文件', f: { '-t': '指定字段分隔符', '-1': '指定文件 1 的连接列', '-2': '指定文件 2 的连接列', '-a': '同时输出未匹配的行', '-i': '比较时忽略大小写' } },
|
|
52
|
+
echo: { d: '输出一行文本', f: { '-n': '不输出末尾换行符', '-e': '解释反斜杠转义字符', '-E': '不解释转义字符(默认)' } },
|
|
53
|
+
printf: { d: '按格式字符串输出文本', f: {} },
|
|
54
|
+
|
|
55
|
+
// ===== Shell 与环境 =====
|
|
56
|
+
env: { d: '显示环境变量或在修改后的环境中运行程序', f: { '-i': '清空环境后再运行', '-u': '删除指定变量后运行' } },
|
|
57
|
+
export: { d: '设置环境变量并导出给子进程', f: { '-n': '取消变量的导出属性', '-p': '列出所有已导出变量' } },
|
|
58
|
+
unset: { d: '删除变量或函数', f: { '-v': '删除变量(默认)', '-f': '删除函数' } },
|
|
59
|
+
alias: { d: '定义或查看命令别名', f: { '-p': '列出所有已定义别名' } },
|
|
60
|
+
unalias: { d: '删除命令别名', f: { '-a': '删除所有别名' } },
|
|
61
|
+
history: { d: '查看或管理命令历史', f: { '-c': '清空当前历史列表', '-d': '删除指定序号的条目', '-w': '把历史写入历史文件', '-a': '追加本次会话的新历史' } },
|
|
62
|
+
source: { d: '在当前 Shell 中执行脚本(等价于 .)', f: {} },
|
|
63
|
+
eval: { d: '把参数拼接成命令后执行', f: {}, danger: '会执行拼接后的任意字符串,注意注入风险' },
|
|
64
|
+
exec: { d: '用新程序替换当前 Shell 进程', f: {} },
|
|
65
|
+
set: { d: '设置 Shell 选项或位置参数', f: { '-e': '命令出错时立即退出', '-u': '引用未定义变量时报错', '-x': '打印每条执行的命令', '-o': '设置选项,如 pipefail', '-C': '禁止重定向覆盖已有文件' } },
|
|
66
|
+
shift: { d: '左移脚本的位置参数', f: {} },
|
|
67
|
+
read: { d: '从标准输入读取一行并赋值给变量', f: { '-r': '不把反斜杠当转义符', '-p': '显示提示语', '-s': '静默输入,不回显(适合密码)', '-t': '设置超时秒数', '-a': '把输入读入数组' } },
|
|
68
|
+
test: { d: '判断条件表达式(等价于 [ ])', f: {} },
|
|
69
|
+
expr: { d: '计算整数表达式或做字符串操作', f: {} },
|
|
70
|
+
true: { d: '返回成功状态码 0', f: {} },
|
|
71
|
+
false: { d: '返回失败状态码 1', f: {} },
|
|
72
|
+
sleep: { d: '暂停指定时长(支持 s/m/h/d 后缀)', f: {} },
|
|
73
|
+
date: { d: '显示或设置系统日期时间', f: { '-d': '解析并显示指定时间字符串', '-u': '使用 UTC 时间', '-s': '设置系统时间', '-R': '输出 RFC 邮件格式' } },
|
|
74
|
+
cal: { d: '显示日历', f: { '-y': '显示全年日历', '-3': '显示上月、本月和下月', '-m': '以周一作为每周第一天', '-j': '显示儒略日' } },
|
|
75
|
+
time: { d: '统计命令执行的耗时', f: { '-p': '以 POSIX 格式输出' } },
|
|
76
|
+
timeout: { d: '限制命令运行时长,超时则终止', f: { '-s': '超时时发送的信号', '-k': '宽限期后仍未退出则发 KILL' } },
|
|
77
|
+
watch: { d: '周期性执行命令并全屏显示结果', f: { '-n': '设置刷新间隔秒数', '-d': '高亮发生变化的部分', '-t': '不显示顶部标题栏' } },
|
|
78
|
+
nohup: { d: '忽略挂断信号,退出终端后继续运行', f: {} },
|
|
79
|
+
jobs: { d: '列出当前 Shell 的后台任务', f: { '-l': '同时显示进程 PID', '-p': '只显示 PID', '-r': '只列出运行中的任务', '-s': '只列出已停止的任务' } },
|
|
80
|
+
bg: { d: '把已停止的任务放到后台继续运行', f: {} },
|
|
81
|
+
fg: { d: '把后台任务调回前台运行', f: {} },
|
|
82
|
+
|
|
83
|
+
// ===== 进程与系统监控 =====
|
|
84
|
+
kill: { d: '向进程发送信号(默认终止)', f: { '-l': '列出所有信号名称', '-s': '指定要发送的信号', '-9': '强制终止(SIGKILL)', '-15': '正常终止(SIGTERM,默认)' }, danger: '强制终止可能导致数据丢失' },
|
|
85
|
+
killall: { d: '按名称终止进程', f: { '-i': '终止前逐个询问', '-s': '指定发送的信号', '-u': '只终止指定用户的进程', '-v': '显示终止结果' }, danger: '按名称批量终止,可能误杀同名进程' },
|
|
86
|
+
pkill: { d: '按名称或其他属性终止进程', f: { '-f': '匹配完整命令行而非仅进程名', '-u': '只终止指定用户的进程', '-x': '精确匹配进程名', '-9': '强制终止(SIGKILL)' }, danger: '会终止所有匹配的进程,请确认匹配范围' },
|
|
87
|
+
pgrep: { d: '按名称或其他属性查找进程 PID', f: { '-f': '匹配完整命令行', '-u': '按用户过滤', '-l': '同时显示进程名', '-a': '显示完整命令行', '-x': '精确匹配进程名' } },
|
|
88
|
+
pidof: { d: '按进程名查找正在运行的 PID', f: { '-s': '只返回一个 PID' } },
|
|
89
|
+
ps: { d: '查看当前进程快照', f: { '-e': '显示所有进程', '-f': '完整格式输出', '-u': '按用户过滤', '-p': '按 PID 过滤', '--sort': '按指定字段排序', 'aux': 'BSD 风格,显示所有进程详情' } },
|
|
90
|
+
top: { d: '实时动态查看进程与资源占用', f: { '-d': '设置刷新间隔秒数', '-n': '刷新 N 次后退出', '-p': '只监控指定 PID', '-u': '按用户过滤', '-b': '批处理模式,适合重定向', '-H': '显示线程级别' } },
|
|
91
|
+
htop: { d: '增强版交互式进程查看器', f: { '-d': '刷新间隔(单位 0.1 秒)', '-u': '按用户过滤', '-p': '只监控指定 PID', '-t': '以树状视图显示' } },
|
|
92
|
+
uptime: { d: '查看系统运行时长与平均负载', f: { '-p': '以友好格式显示运行时长', '-s': '显示系统开机时间点' } },
|
|
93
|
+
free: { d: '查看内存与交换空间使用情况', f: { '-h': '以可读单位显示', '-m': '以 MB 为单位', '-g': '以 GB 为单位', '-s': '按间隔持续刷新', '-t': '显示总计行' } },
|
|
94
|
+
vmstat: { d: '报告虚拟内存、进程与 CPU 统计', f: { '-a': '显示活跃与非活跃内存', '-s': '显示统计汇总', '-d': '显示磁盘统计', '-w': '加宽输出便于阅读' } },
|
|
95
|
+
iostat: { d: '报告 CPU 与磁盘 I/O 统计', f: { '-x': '显示扩展统计', '-c': '只看 CPU 报告', '-d': '只看磁盘报告', '-m': '以 MB 为单位显示' } },
|
|
96
|
+
df: { d: '查看文件系统的磁盘空间使用', f: { '-h': '以可读单位显示', '-T': '显示文件系统类型', '-i': '显示 inode 使用情况', '-t': '只显示指定类型的文件系统' } },
|
|
97
|
+
du: { d: '统计目录或文件占用的磁盘空间', f: { '-h': '以可读单位显示', '-s': '只显示总计', '-a': '包含每个文件', '-c': '最后显示总计', '--max-depth': '限制统计的目录深度' } },
|
|
98
|
+
lsblk: { d: '以树状列出块设备(磁盘与分区)', f: { '-f': '显示文件系统与 UUID 信息', '-a': '包含空设备', '-o': '自定义输出列', '-m': '显示属主与权限信息' } },
|
|
99
|
+
blkid: { d: '查看块设备的 UUID 与文件系统类型', f: { '-o': '指定输出格式(如 value)', '-s': '只显示指定标签' } },
|
|
100
|
+
mount: { d: '挂载文件系统', f: { '-t': '指定文件系统类型', '-o': '指定挂载选项', '-a': '挂载 fstab 中所有项', '-r': '以只读方式挂载', '--bind': '把目录绑定挂载到另一处' } },
|
|
101
|
+
umount: { d: '卸载已挂载的文件系统', f: { '-l': '延迟卸载,待空闲后完成', '-f': '强制卸载' }, danger: '设备使用中强行卸载可能丢失未写入数据' },
|
|
102
|
+
fdisk: { d: '管理磁盘分区表(MBR/GPT)', f: { '-l': '列出分区表', '-u': '以扇区为单位显示' }, danger: '修改分区表可能导致数据丢失' },
|
|
103
|
+
parted: { d: '磁盘分区管理(支持 GPT 与大磁盘)', f: { '-l': '列出分区信息', '-s': '脚本模式,不交互提问' }, danger: '分区操作可能导致数据丢失' },
|
|
104
|
+
mkfs: { d: '在分区上创建文件系统(格式化)', f: { '-t': '指定文件系统类型(如 ext4、xfs)', '-L': '设置卷标' }, danger: '会清空目标分区上的所有数据' },
|
|
105
|
+
fsck: { d: '检查并修复文件系统', f: { '-y': '对所有提问自动回答 yes', '-n': '只检查不做任何修复', '-f': '强制检查即使标记为干净', '-t': '指定文件系统类型' }, danger: '对已挂载的分区修复可能损坏数据' },
|
|
106
|
+
swapon: { d: '启用交换分区或交换文件', f: { '-a': '启用 fstab 中所有交换项', '-s': '显示交换使用摘要' } },
|
|
107
|
+
swapoff: { d: '关闭交换分区或交换文件', f: { '-a': '关闭所有交换项' } },
|
|
108
|
+
dd: { d: '按块复制与转换数据(常用于写镜像)', f: { 'if': '输入文件', 'of': '输出文件', 'bs': '每次读写的块大小', 'count': '复制的块数量', 'status': '进度显示级别(如 progress)', 'conv': '转换选项(如 fsync)' }, danger: '写错目标设备会覆盖数据' },
|
|
109
|
+
shred: { d: '反复覆写文件以掩盖数据', f: { '-n': '指定覆写次数', '-z': '最后补一次全零覆写', '-u': '覆写后删除文件', '-v': '显示覆写进度' }, danger: '覆写后数据无法恢复,对 SSD 效果有限' },
|
|
110
|
+
sync: { d: '把内存中的缓冲数据刷写到磁盘', f: {} },
|
|
111
|
+
chroot: { d: '切换根目录后运行命令', f: {} },
|
|
112
|
+
uname: { d: '显示系统内核与架构信息', f: { '-a': '显示全部信息', '-r': '显示内核版本', '-m': '显示硬件架构', '-s': '显示内核名称', '-n': '显示主机名' } },
|
|
113
|
+
hostname: { d: '显示或设置系统主机名', f: { '-I': '显示所有网卡 IP 地址', '-f': '显示完整域名 FQDN', '-s': '显示短主机名' } },
|
|
114
|
+
hostnamectl: { d: '查看或设置系统主机名', f: { 'status': '查看主机名与系统信息', 'set-hostname': '设置主机名' } },
|
|
115
|
+
whoami: { d: '显示当前有效用户名', f: {} },
|
|
116
|
+
id: { d: '显示用户与组的 ID 信息', f: { '-u': '只显示用户 UID', '-g': '只显示主组 GID', '-G': '显示所有所属组 ID', '-n': '显示名称而非数字 ID' } },
|
|
117
|
+
groups: { d: '显示用户所属的组', f: {} },
|
|
118
|
+
who: { d: '显示当前登录的用户', f: { '-a': '显示全部信息', '-b': '显示上次系统启动时间', '-q': '只列用户名与数量' } },
|
|
119
|
+
w: { d: '显示登录用户及其正在执行的操作', f: { '-h': '不显示表头', '-s': '使用简洁格式' } },
|
|
120
|
+
last: { d: '查看最近登录记录', f: { '-n': '限制显示条数', '-f': '指定登录日志文件', '-x': '显示关机与运行级别记录' } },
|
|
121
|
+
logname: { d: '显示当前登录用户名', f: {} },
|
|
122
|
+
users: { d: '显示当前登录的用户名列表', f: {} },
|
|
123
|
+
tty: { d: '显示当前终端对应的设备文件名', f: { '-s': '静默模式,仅返回状态码' } },
|
|
124
|
+
|
|
125
|
+
// ===== 用户、权限与内核 =====
|
|
126
|
+
su: { d: '切换用户身份', f: { '-': '登录式切换并加载目标用户环境', '-l': '同 -,登录式切换', '-c': '以目标用户执行一条命令' } },
|
|
127
|
+
sudo: { d: '以其他用户(默认 root)权限执行命令', f: { '-u': '指定执行用户', '-i': '模拟目标用户的登录环境', '-s': '运行目标用户的 Shell', '-l': '列出当前用户可用的权限', '-k': '清除已缓存的凭证' }, danger: '以高权限执行命令,请确认操作内容' },
|
|
128
|
+
passwd: { d: '修改用户密码', f: { '-l': '锁定账户密码', '-u': '解锁账户密码', '-d': '删除密码(设为空)', '-e': '强制下次登录时修改密码', '-S': '查看密码状态' } },
|
|
129
|
+
useradd: { d: '创建新用户', f: { '-m': '同时创建家目录', '-s': '指定登录 Shell', '-g': '指定主组', '-G': '指定附加组', '-u': '指定 UID', '-d': '指定家目录路径', '-r': '创建系统账户' } },
|
|
130
|
+
usermod: { d: '修改已有用户的属性', f: { '-a': '与 -G 连用,追加而非覆盖附加组', '-G': '设置附加组列表', '-s': '修改登录 Shell', '-l': '修改登录名', '-L': '锁定账户', '-U': '解锁账户' } },
|
|
131
|
+
userdel: { d: '删除用户账户', f: { '-r': '连同家目录和邮件一起删除', '-f': '强制删除' }, danger: '删除用户及其家目录后难以恢复' },
|
|
132
|
+
groupadd: { d: '创建新用户组', f: { '-g': '指定 GID', '-r': '创建系统组' } },
|
|
133
|
+
chown: { d: '修改文件或目录的属主与属组', f: { '-R': '递归修改', '-v': '显示处理过程', '-c': '仅显示实际发生的更改', '--from': '仅当当前属主匹配时才修改' } },
|
|
134
|
+
chmod: { d: '修改文件或目录的权限', f: { '-R': '递归修改', '-v': '显示处理过程', '-c': '仅显示实际发生的更改', '--reference': '参照另一文件的权限设置' }, danger: '权限设置不当可能带来安全风险' },
|
|
135
|
+
chgrp: { d: '修改文件或目录的属组', f: { '-R': '递归修改', '-v': '显示处理过程' } },
|
|
136
|
+
umask: { d: '查看或设置默认权限掩码', f: { '-S': '以符号形式显示掩码' } },
|
|
137
|
+
setfacl: { d: '设置文件的访问控制列表 ACL', f: { '-m': '修改或添加 ACL 规则', '-x': '删除指定 ACL 规则', '-b': '删除所有扩展 ACL', '-R': '递归应用', '-d': '设置默认 ACL(用于目录)' } },
|
|
138
|
+
getfacl: { d: '查看文件的访问控制列表 ACL', f: { '-R': '递归显示', '-a': '显示访问 ACL', '-d': '显示默认 ACL' } },
|
|
139
|
+
getenforce: { d: '查看 SELinux 当前运行模式', f: {} },
|
|
140
|
+
setenforce: { d: '临时切换 SELinux 模式(0 宽容 1 强制)', f: {}, danger: '关闭 SELinux 会降低系统安全防护' },
|
|
141
|
+
sysctl: { d: '查看或修改内核运行参数', f: { '-a': '显示所有内核参数', '-w': '写入参数值', '-p': '从配置文件加载参数', '-n': '只输出值不输出键名' }, danger: '错误修改内核参数可能影响系统稳定' },
|
|
142
|
+
ulimit: { d: '查看或设置 Shell 资源限制', f: { '-a': '显示所有限制', '-n': '最大打开文件数', '-u': '最大用户进程数', '-c': 'core 文件大小上限' } },
|
|
143
|
+
dmesg: { d: '查看内核环形缓冲区日志', f: { '-T': '显示可读时间戳', '-w': '实时跟踪新日志', '--level': '按级别过滤(如 err)', '-c': '读取后清空缓冲区' } },
|
|
144
|
+
lsmod: { d: '列出已加载的内核模块', f: {} },
|
|
145
|
+
modprobe: { d: '智能加载或卸载内核模块(含依赖)', f: { '-r': '卸载模块', '-n': '试运行,不实际执行' } },
|
|
146
|
+
insmod: { d: '手动加载指定内核模块文件', f: {} },
|
|
147
|
+
rmmod: { d: '卸载内核模块', f: {} },
|
|
148
|
+
lspci: { d: '列出 PCI 设备信息', f: { '-v': '显示详细信息', '-nn': '同时显示厂商与设备 ID', '-k': '显示使用的内核驱动', '-t': '以树状显示' } },
|
|
149
|
+
lsusb: { d: '列出 USB 设备信息', f: { '-v': '显示详细信息', '-t': '以树状显示', '-d': '按厂商:产品 ID 过滤' } },
|
|
150
|
+
lscpu: { d: '显示 CPU 架构信息', f: { '-e': '按每个 CPU 列表输出', '-p': '以可解析格式输出' } },
|
|
151
|
+
lshw: { d: '列出详细硬件配置', f: { '-short': '输出简洁列表', '-C': '按类别显示(如 disk、memory)', '-html': '输出 HTML 格式' } },
|
|
152
|
+
dmidecode: { d: '读取 DMI/SMBIOS 硬件信息', f: { '-t': '按类型显示(如 memory、bios)', '-s': '按关键字直接取值', '-q': '精简输出' } },
|
|
153
|
+
|
|
154
|
+
// ===== 网络 =====
|
|
155
|
+
ip: { d: '查看和配置网络(地址、路由、网卡)', f: { 'addr': '查看或配置 IP 地址', 'route': '查看或配置路由', 'link': '查看或配置网卡', '-s': '显示统计信息', '-4': '仅 IPv4', '-6': '仅 IPv6', '-c': '彩色输出' } },
|
|
156
|
+
ifconfig: { d: '查看或配置网卡(旧工具,建议用 ip)', f: { '-a': '显示所有网卡(含未启用)', 'up': '启用网卡', 'down': '禁用网卡' } },
|
|
157
|
+
ping: { d: '测试与目标主机的网络连通性', f: { '-c': '指定发送次数', '-i': '设置发送间隔秒数', '-s': '设置数据包大小', '-W': '设置等待超时秒数', '-4': '仅使用 IPv4', '-6': '仅使用 IPv6' } },
|
|
158
|
+
traceroute: { d: '跟踪到目标主机经过的路由', f: { '-n': '不解析域名直接显示 IP', '-m': '设置最大跳数', '-w': '设置等待超时秒数', '-I': '使用 ICMP 探测', '-T': '使用 TCP 探测' } },
|
|
159
|
+
ss: { d: '查看套接字与网络连接统计', f: { '-l': '只看监听中的端口', '-t': '只看 TCP', '-u': '只看 UDP', '-n': '以数字形式显示不解析', '-p': '显示占用进程', '-a': '显示所有连接', '-s': '显示统计摘要' } },
|
|
160
|
+
netstat: { d: '查看网络连接、路由与接口统计', f: { '-l': '只看监听端口', '-t': '只看 TCP', '-u': '只看 UDP', '-n': '以数字形式显示', '-p': '显示占用进程', '-r': '显示路由表', '-a': '显示所有连接' } },
|
|
161
|
+
lsof: { d: '列出进程打开的文件与网络连接', f: { '-i': '查看网络连接', '-p': '按 PID 查看', '-u': '按用户查看', '+D': '查看目录下被打开的文件', '-t': '只输出 PID' } },
|
|
162
|
+
nc: { d: '网络调试与端口测试工具', f: { '-l': '监听模式', '-p': '指定端口', '-u': '使用 UDP', '-z': '只扫描不发送数据', '-v': '显示详细信息', '-w': '设置超时秒数' } },
|
|
163
|
+
dig: { d: '查询 DNS 解析记录', f: { '+short': '简洁输出结果', '+trace': '跟踪完整解析过程', '-t': '指定记录类型(如 MX)', '-x': '反向解析 IP' } },
|
|
164
|
+
nslookup: { d: '查询 DNS 解析(交互式或单次)', f: {} },
|
|
165
|
+
curl: { d: '通过 URL 传输数据的命令行工具', f: { '-O': '以远程文件名保存', '-o': '指定保存的文件名', '-I': '只获取响应头', '-X': '指定请求方法', '-H': '添加请求头', '-d': '发送 POST 数据', '-L': '跟随重定向', '-s': '静默模式不显示进度', '-u': '指定认证用户名密码', '-k': '跳过 TLS 证书校验' } },
|
|
166
|
+
wget: { d: '从网络下载文件', f: { '-O': '指定保存的文件名', '-c': '断点续传', '-b': '后台下载', '-q': '静默模式', '-r': '递归下载', '--limit-rate': '限制下载速度', '-i': '从文件读取 URL 列表' } },
|
|
167
|
+
ssh: { d: '安全远程登录主机', f: { '-p': '指定端口', '-i': '指定私钥文件', '-v': '输出调试信息', '-L': '本地端口转发', '-R': '远程端口转发', '-N': '不执行远程命令(仅转发)', '-X': '转发 X11 图形', '-o': '指定配置项' } },
|
|
168
|
+
scp: { d: '基于 SSH 在主机间复制文件', f: { '-P': '指定端口', '-r': '递归复制目录', '-i': '指定私钥文件', '-C': '压缩传输', '-p': '保留文件属性' } },
|
|
169
|
+
sftp: { d: '基于 SSH 的交互式文件传输', f: { '-P': '指定端口', '-i': '指定私钥文件', '-b': '批处理模式' } },
|
|
170
|
+
rsync: { d: '高效同步文件与目录(支持增量)', f: { '-a': '归档模式保留属性', '-v': '显示同步过程', '-z': '传输时压缩', '-P': '显示进度并支持续传', '-e': '指定远程 Shell', '--delete': '删除目标端多余文件', '--exclude': '排除匹配的文件' } },
|
|
171
|
+
tcpdump: { d: '抓取并分析网络数据包', f: { '-i': '指定网卡(any 为全部)', '-n': '不解析域名', '-nn': '不解析域名和端口', '-c': '抓取指定数量后停止', '-w': '把抓包写入文件', '-r': '读取抓包文件' } },
|
|
172
|
+
ufw: { d: '管理 Ubuntu 简易防火墙', f: { 'status': '查看防火墙状态', 'allow': '放行端口或来源', 'deny': '拒绝端口或来源', 'enable': '启用防火墙', 'disable': '关闭防火墙', 'delete': '删除规则' }, danger: '规则配置不当可能导致无法远程登录' },
|
|
173
|
+
iptables: { d: '配置 IPv4 防火墙规则', f: { '-L': '列出规则', '-A': '追加规则', '-D': '删除规则', '-I': '插入规则', '-F': '清空规则', '-n': '以数字形式显示', '-P': '设置链默认策略' }, danger: '清空或误配规则可能中断网络或远程连接' },
|
|
174
|
+
'ssh-keygen': { d: '生成 SSH 密钥对', f: { '-t': '指定密钥类型(如 ed25519)', '-b': '指定密钥位数', '-C': '添加注释', '-f': '指定输出文件' } },
|
|
175
|
+
|
|
176
|
+
// ===== 服务与计划任务 =====
|
|
177
|
+
systemctl: { d: '管理 systemd 服务与系统状态', f: { 'status': '查看服务状态', 'start': '启动服务', 'stop': '停止服务', 'restart': '重启服务', 'enable': '设置开机自启', 'disable': '取消开机自启', 'list-units': '列出已加载单元', '--failed': '列出失败的单元', '--user': '操作用户级服务' } },
|
|
178
|
+
service: { d: '传统 SysV 服务管理入口', f: { 'status': '查看服务状态', 'start': '启动服务', 'stop': '停止服务', 'restart': '重启服务', '--status-all': '列出所有服务状态' } },
|
|
179
|
+
journalctl: { d: '查看 systemd 日志', f: { '-u': '按服务单元过滤', '-f': '实时跟踪新日志', '-n': '显示最后 N 行', '-e': '跳到日志末尾', '--since': '指定起始时间', '--until': '指定截止时间', '-p': '按优先级过滤(如 err)', '-k': '只看内核日志', '-b': '只看本次启动以来' } },
|
|
180
|
+
crontab: { d: '管理当前用户的定时任务', f: { '-l': '列出定时任务', '-e': '编辑定时任务', '-r': '删除全部定时任务', '-u': '指定用户', '-i': '删除前询问确认' }, danger: 'crontab -r 会清空全部定时任务' },
|
|
181
|
+
at: { d: '在指定时间执行一次性任务', f: { '-l': '列出待执行任务', '-d': '删除指定任务', '-f': '从文件读取要执行的命令' } },
|
|
182
|
+
timedatectl: { d: '查看和设置系统时间与时区', f: { 'status': '查看时间设置', 'set-time': '设置时间', 'set-timezone': '设置时区', 'set-ntp': '开关 NTP 同步', 'list-timezones': '列出可用时区' } },
|
|
183
|
+
|
|
184
|
+
// ===== 软件包管理 =====
|
|
185
|
+
apt: { d: 'Debian/Ubuntu 软件包管理', f: { 'install': '安装软件包', 'remove': '卸载软件包', 'update': '刷新软件源索引', 'upgrade': '升级已装软件包', 'search': '搜索软件包', 'show': '查看包详情', 'list': '列出软件包', 'autoremove': '清理不再需要的依赖' } },
|
|
186
|
+
'apt-get': { d: 'Debian/Ubuntu 底层包管理命令', f: { 'install': '安装软件包', 'remove': '卸载软件包', 'update': '刷新软件源索引', 'upgrade': '升级软件包', 'autoremove': '清理无用依赖', 'purge': '卸载并删除配置', '-y': '自动确认不提问' } },
|
|
187
|
+
dpkg: { d: 'Debian 底层包安装与查询工具', f: { '-i': '安装 deb 包', '-r': '卸载软件包', '-P': '卸载并清除配置', '-l': '列出已安装的包', '-L': '列出包安装的所有文件', '-s': '查看包状态' } },
|
|
188
|
+
yum: { d: 'RHEL/CentOS 旧版包管理器', f: { 'install': '安装软件包', 'remove': '卸载软件包', 'update': '升级软件包', 'search': '搜索软件包', 'info': '查看包详情', '-y': '自动确认不提问' } },
|
|
189
|
+
dnf: { d: 'RHEL/Fedora 新一代包管理器', f: { 'install': '安装软件包', 'remove': '卸载软件包', 'update': '升级软件包', 'search': '搜索软件包', 'info': '查看包详情', '-y': '自动确认不提问' } },
|
|
190
|
+
rpm: { d: 'RPM 包安装与查询', f: { '-i': '安装软件包', '-U': '升级软件包', '-e': '卸载软件包', '-q': '查询软件包', '-a': '配合 -q 查询所有已装包', '-v': '显示详细信息', '-h': '显示安装进度' } },
|
|
191
|
+
pip: { d: 'Python 包管理器', f: { 'install': '安装包', 'uninstall': '卸载包', 'list': '列出已装包', 'show': '查看包信息', 'freeze': '导出依赖清单', '-U': '升级到最新版', '-r': '按需求文件安装' } },
|
|
192
|
+
pip3: { d: 'Python 3 的 pip(多数系统同 pip)', f: {} },
|
|
193
|
+
npm: { d: 'Node.js 包管理器', f: { 'install': '安装依赖', 'uninstall': '卸载依赖', 'run': '运行脚本', 'init': '初始化项目', '-g': '全局安装', '-D': '安装为开发依赖' } },
|
|
194
|
+
|
|
195
|
+
// ===== 开发与运行时 =====
|
|
196
|
+
git: { d: '分布式版本控制系统', f: { 'status': '查看工作区状态', 'add': '暂存改动', 'commit': '提交改动', 'push': '推送到远程', 'pull': '拉取并合并', 'clone': '克隆仓库', 'branch': '分支管理', 'checkout': '切换分支或还原文件', 'log': '查看提交历史', 'stash': '暂存当前现场', 'diff': '查看差异', 'merge': '合并分支' } },
|
|
197
|
+
docker: { d: '容器化应用运行与管理', f: { 'ps': '列出容器', 'images': '列出镜像', 'run': '运行容器', 'exec': '在运行中容器内执行命令', 'build': '构建镜像', 'pull': '拉取镜像', 'logs': '查看容器日志', 'stop': '停止容器', 'rm': '删除容器', 'rmi': '删除镜像', 'system prune': '清理无用资源' }, danger: '删除类子命令会移除容器、镜像或数据' },
|
|
198
|
+
node: { d: '运行 JavaScript 的 Node.js 运行时', f: { '-e': '执行脚本字符串', '-v': '显示版本', '--inspect': '开启调试器' } },
|
|
199
|
+
python: { d: 'Python 解释器', f: { '-c': '执行代码字符串', '-m': '以模块方式运行', '-V': '显示版本', '-i': '执行后进入交互模式' } },
|
|
200
|
+
python3: { d: 'Python 3 解释器', f: { '-c': '执行代码字符串', '-m': '以模块方式运行', '-V': '显示版本' } },
|
|
201
|
+
gcc: { d: 'GNU C 编译器', f: { '-o': '指定输出文件', '-c': '只编译不链接', '-g': '生成调试信息', '-O2': '开启二级优化', '-Wall': '开启常见警告', '-I': '添加头文件目录', '-L': '添加库目录', '-l': '链接指定库' } },
|
|
202
|
+
make: { d: '按 Makefile 自动化构建', f: { '-j': '指定并行任务数', '-f': '指定 Makefile 文件', '-C': '切换到指定目录执行', '-n': '试运行只打印命令', '-B': '强制重新构建所有目标' } },
|
|
203
|
+
kubectl: { d: '管理 Kubernetes 集群', f: { 'get': '查看资源', 'describe': '查看资源详情', 'logs': '查看 Pod 日志', 'apply': '应用配置', 'delete': '删除资源', 'exec': '进入容器执行命令', '-n': '指定命名空间', '-A': '所有命名空间' }, danger: 'delete 会直接删除集群资源' },
|
|
204
|
+
mysql: { d: 'MySQL 命令行客户端', f: { '-u': '指定用户名', '-p': '提示输入密码', '-h': '指定主机', '-P': '指定端口', '-e': '执行 SQL 后退出', '-D': '指定数据库' } },
|
|
205
|
+
|
|
206
|
+
// ===== 压缩、归档与校验 =====
|
|
207
|
+
tar: { d: '打包与解包归档文件', f: { '-c': '创建归档', '-x': '解包归档', '-t': '列出归档内容', '-z': '用 gzip 压缩或解压', '-j': '用 bzip2 压缩或解压', '-J': '用 xz 压缩或解压', '-f': '指定归档文件名', '-v': '显示处理过程', '-C': '指定解包目标目录' } },
|
|
208
|
+
gzip: { d: '压缩文件为 gzip 格式', f: { '-d': '解压', '-k': '保留原文件', '-9': '最高压缩比', '-1': '最快压缩', '-c': '输出到标准输出' } },
|
|
209
|
+
gunzip: { d: '解压 gzip 文件(等价 gzip -d)', f: { '-k': '保留原压缩文件', '-c': '输出到标准输出' } },
|
|
210
|
+
bzip2: { d: '压缩文件为 bzip2 格式', f: { '-d': '解压', '-k': '保留原文件', '-9': '最高压缩比' } },
|
|
211
|
+
xz: { d: '压缩文件为 xz 格式', f: { '-d': '解压', '-k': '保留原文件', '-9': '最高压缩比' } },
|
|
212
|
+
zip: { d: '打包压缩为 zip 格式', f: { '-r': '递归包含目录', '-e': '加密压缩', '-q': '静默模式', '-u': '更新包内已有文件' } },
|
|
213
|
+
unzip: { d: '解压 zip 压缩包', f: { '-l': '列出压缩包内容', '-d': '解压到指定目录', '-o': '覆盖已有文件不询问', '-q': '静默模式', '-P': '指定解压密码' } },
|
|
214
|
+
zcat: { d: '直接查看 gzip 压缩文件内容', f: {} },
|
|
215
|
+
openssl: { d: '加密、证书与摘要工具箱', f: { 'rand': '生成随机数', 'enc': '对称加解密', 'dgst': '计算消息摘要', 'x509': '证书处理', 's_client': '测试 TLS 连接', 'genrsa': '生成 RSA 私钥' } },
|
|
216
|
+
gpg: { d: 'GNU 加密与签名工具', f: { '-c': '对称加密', '-e': '公钥加密', '-d': '解密', '--sign': '签名', '--verify': '验证签名', '--list-keys': '列出密钥' } },
|
|
217
|
+
sha256sum: { d: '计算或校验 SHA256 摘要', f: { '-c': '按清单文件校验', '-b': '以二进制模式读取' } },
|
|
218
|
+
md5sum: { d: '计算或校验 MD5 摘要(不宜用于安全场景)', f: { '-c': '按清单文件校验' } },
|
|
219
|
+
base64: { d: 'Base64 编解码', f: { '-d': '解码', '-w': '指定换行宽度(0 为不换行)' } },
|
|
220
|
+
xxd: { d: '以十六进制查看或还原文件', f: { '-r': '把十六进制转回二进制', '-p': '纯十六进制输出', '-l': '限制处理长度', '-g': '按字节分组显示' } },
|
|
221
|
+
strings: { d: '提取文件中的可打印字符串', f: { '-n': '指定最小字符串长度', '-a': '扫描整个文件' } },
|
|
222
|
+
|
|
223
|
+
// ===== 编辑器、终端与杂项 =====
|
|
224
|
+
vim: { d: '功能强大的终端编辑器', f: { '-R': '以只读模式打开', '-d': '比较模式(vimdiff)', '-u': '指定 vimrc 配置文件' } },
|
|
225
|
+
vi: { d: '经典终端编辑器(多数系统指向 vim)', f: {} },
|
|
226
|
+
nano: { d: '简单易用的终端编辑器', f: { '-l': '显示行号', '-m': '启用鼠标支持', '-B': '保存时备份原文件' } },
|
|
227
|
+
man: { d: '查看命令手册页', f: { '-k': '按关键词搜索手册(同 apropos)', '-w': '显示手册页文件路径' } },
|
|
228
|
+
whatis: { d: '按名称查命令的一句话说明', f: {} },
|
|
229
|
+
apropos: { d: '按关键词搜索手册页', f: {} },
|
|
230
|
+
screen: { d: '终端多会话管理', f: { '-S': '指定会话名', '-r': '恢复已分离的会话', '-ls': '列出所有会话', '-d': '分离指定会话' } },
|
|
231
|
+
tmux: { d: '终端复用器', f: { 'new': '新建会话', 'attach': '接入已有会话', 'ls': '列出会话', 'kill-session': '结束会话' } },
|
|
232
|
+
pstree: { d: '以树状显示进程关系', f: { '-p': '显示进程 PID', '-u': '显示用户切换', '-a': '显示命令行参数' } },
|
|
233
|
+
ldd: { d: '查看可执行文件的共享库依赖', f: {}, danger: '不要对不可信的可执行文件使用' },
|
|
234
|
+
truncate: { d: '截断或扩展文件到指定大小', f: { '-s': '指定目标大小', '-c': '文件不存在时不创建' }, danger: '截断会清空文件内容' },
|
|
235
|
+
shutdown: { d: '关机或重启系统', f: { '-h': '关机', '-r': '重启', '-c': '取消已计划的关机' }, danger: '会中断当前所有会话' },
|
|
236
|
+
reboot: { d: '立即重启系统', f: {}, danger: '会中断当前所有会话' },
|
|
237
|
+
poweroff: { d: '立即关闭系统电源', f: {}, danger: '会中断当前所有会话' },
|
|
238
|
+
sensors: { d: '显示温度、风扇等传感器读数', f: {} },
|
|
239
|
+
'systemd-analyze': { d: '分析系统启动耗时', f: { 'blame': '按耗时列出各启动项', 'time': '显示启动总耗时', 'critical-chain': '显示关键链' } },
|
|
240
|
+
findmnt: { d: '查看已挂载的文件系统', f: { '-l': '以列表格式输出', '-t': '按文件系统类型过滤', '-T': '按路径查找挂载点' } },
|
|
241
|
+
upower: { d: '查看电池与电源信息', f: { '-i': '查看设备详情', '-e': '列出电源设备' } },
|
|
242
|
+
loginctl: { d: '管理 systemd 登录会话', f: { 'lock-session': '锁定会话(锁屏)', 'unlock-session': '解锁会话', 'list-sessions': '列出会话', 'terminate-session': '终止会话' } },
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// 危险参数模式:re 为正则源码字符串(消费方以 new RegExp(re, 'i') 编译)。
|
|
246
|
+
export const DANGER_RULES = [
|
|
247
|
+
{ re: '\\brm\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*\\s+)+(?:/|/\\*|~|\\$HOME|/home)(?:\\s|;|$)', warn: '正在删除根目录或家目录,可能导致系统崩溃或数据全部丢失' },
|
|
248
|
+
{ re: '\\brm\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*\\s+)+/(?:etc|usr|var|boot|bin|lib|opt|sbin|root)(?:/|\\s|;|$)', warn: '删除系统目录会破坏操作系统' },
|
|
249
|
+
{ re: '\\brm\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*\\s+)+(?:\\*|\\.)(?:\\s|;|$)', warn: '会删除当前目录下全部内容,请确认所在目录' },
|
|
250
|
+
{ re: '\\bdd\\b[^|;&]*\\bof=/dev/', warn: 'dd 直接写入块设备,写错目标会覆盖整盘数据' },
|
|
251
|
+
{ re: '\\bmkfs(?:\\.[a-z0-9]+)?\\b[^|;&]*/dev/', warn: '格式化会清空目标分区上的所有数据' },
|
|
252
|
+
{ re: '\\bchmod\\b[^|;&]*\\b777\\b[^|;&]*\\s(?:/|/\\*|~|\\$HOME)(?:\\s|;|$)', warn: '对根目录或家目录开放全部权限,存在严重安全风险' },
|
|
253
|
+
{ re: '\\bchmod\\b[^|;&]*-[a-zA-Z]*R[a-zA-Z]*\\s+777\\b', warn: '递归开放全部权限存在安全风险' },
|
|
254
|
+
{ re: '\\bchown\\b[^|;&]*-[a-zA-Z]*R[a-zA-Z]*\\b[^|;&]*\\s/(?:\\s|;|$)', warn: '递归修改根目录属主会破坏系统权限' },
|
|
255
|
+
{ re: '([:\\w]+)\\(\\)\\s*\\{\\s*\\1\\|\\1&\\s*\\}\\s*;\\s*\\1', warn: '这是 fork 炸弹,会耗尽系统进程资源导致死机' },
|
|
256
|
+
{ re: '>\\s*/dev/(?:sd[a-z]|nvme\\d+n\\d+|vd[a-z]|hd[a-z]|mmcblk\\d+)', warn: '重定向写入块设备会破坏磁盘数据' },
|
|
257
|
+
{ re: '\\b(?:curl|wget)\\b[^|;&]*\\|\\s*(?:sudo\\s+)?(?:sh|bash|zsh|dash)\\b', warn: '直接执行远程脚本,可能运行恶意代码,请先下载审查' },
|
|
258
|
+
{ re: '\\bhistory\\s+-[a-zA-Z]*c', warn: '会清空命令历史,可能影响审计与追溯' },
|
|
259
|
+
{ re: '\\b(?:iptables|ip6tables)\\b[^|;&]*\\s-F\\b', warn: '清空防火墙规则可能使服务暴露或中断现有连接' },
|
|
260
|
+
{ re: '\\buserdel\\b[^|;&]*\\s-[a-zA-Z]*r', warn: '会连同家目录一起删除用户数据' },
|
|
261
|
+
{ re: '\\bcrontab\\b[^|;&]*\\s-[a-zA-Z]*r', warn: '会删除当前用户的全部定时任务' },
|
|
262
|
+
{ re: '\\bgit\\s+push\\b(?=[^|;&]*(?:--force|-f)\\b)(?=[^|;&]*\\b(?:main|master)\\b)', warn: '强推主分支会覆盖远程历史,可能丢失他人提交' },
|
|
263
|
+
{ re: '\\bdocker\\s+system\\s+prune\\b(?=[^|;&]*(?:-a|--all)\\b)(?=[^|;&]*--volumes\\b)', warn: '会删除所有未使用镜像和数据卷,数据不可恢复' },
|
|
264
|
+
{ re: '\\bdocker\\s+rm\\b[^|;&]*\\$\\(\\s*docker\\s+ps', warn: '批量删除容器,未持久化的数据会丢失' },
|
|
265
|
+
{ re: '\\bwipefs\\b[^|;&]*/dev/', warn: '会擦除设备上的文件系统签名' },
|
|
266
|
+
];
|
package/src/core.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// Linux 指令器 — local recognition and query core.
|
|
2
|
+
// Pure logic: intent detection, command explanation, natural-language
|
|
3
|
+
// generation, and the local-first pipeline. No I/O here; the AI adapter
|
|
4
|
+
// is injected by the caller.
|
|
5
|
+
import { COMMANDS, DANGER_RULES } from './commands.js';
|
|
6
|
+
import { NL_RULES } from './nl.js';
|
|
7
|
+
|
|
8
|
+
const CJK = /[\u3400-\u4dbf\u4e00-\u9fff]/;
|
|
9
|
+
const NL_HINT = /(请|帮我|帮忙|怎么|怎样|如何|查看|显示|列出|查找|寻找|搜索|我想|想要|我要|需要|创建|新建|删除|移除|修改|更改|设置|统计|比较|压缩|解压|下载|上传|安装|卸载|更新|升级|重启|关机|结束|终止|杀死|监控|跟踪|实时|占用|权限|属主|密码|用户|服务|进程|端口|磁盘|内存|文件|目录|文件夹|日志|版本|内核|主机|网络|连接|测试|生成|批量|定时|后台|前台|历史|环境|变量|命令|指令|操作|方法|步骤|吗|呢|?|\?)/;
|
|
10
|
+
const SHELL_META = /[|&;<>$`]/;
|
|
11
|
+
const MAX_EXPLAIN = 240;
|
|
12
|
+
const MAX_WARN = 140;
|
|
13
|
+
|
|
14
|
+
const cap = (s, n) => (s.length > n ? s.slice(0, n - 1) + '…' : s);
|
|
15
|
+
|
|
16
|
+
/** Strip leading sudo/env-assignment/nohup/time wrappers; return notes + words. */
|
|
17
|
+
function unwrap(words) {
|
|
18
|
+
const notes = [];
|
|
19
|
+
let i = 0;
|
|
20
|
+
while (i < words.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(words[i])) i++;
|
|
21
|
+
while (i < words.length) {
|
|
22
|
+
const w = words[i];
|
|
23
|
+
if (w === 'sudo') {
|
|
24
|
+
notes.push('以管理员权限执行');
|
|
25
|
+
i++;
|
|
26
|
+
while (i < words.length && /^-[a-zA-Z]$/.test(words[i])) {
|
|
27
|
+
if (words[i] === '-u' || words[i] === '-g') i++;
|
|
28
|
+
i++;
|
|
29
|
+
}
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (w === 'nohup') { notes.push('忽略挂断信号'); i++; continue; }
|
|
33
|
+
if (w === 'time') { notes.push('统计执行耗时'); i++; continue; }
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
return { notes, rest: words.slice(i) };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Split one command segment into words, honoring quotes. */
|
|
40
|
+
function tokenize(seg) {
|
|
41
|
+
const words = [];
|
|
42
|
+
let cur = '';
|
|
43
|
+
let q = null;
|
|
44
|
+
let esc = false;
|
|
45
|
+
let has = false;
|
|
46
|
+
for (const c of seg) {
|
|
47
|
+
if (esc) { cur += c; esc = false; continue; }
|
|
48
|
+
if (c === '\\' && q !== "'") { esc = true; has = true; continue; }
|
|
49
|
+
if (q) { if (c === q) q = null; else cur += c; continue; }
|
|
50
|
+
if (c === '"' || c === "'") { q = c; has = true; continue; }
|
|
51
|
+
if (/\s/.test(c)) { if (has) { words.push(cur); cur = ''; has = false; } continue; }
|
|
52
|
+
cur += c;
|
|
53
|
+
has = true;
|
|
54
|
+
}
|
|
55
|
+
if (has) words.push(cur);
|
|
56
|
+
return words;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Split a full input into [segment, operator, segment, ...] honoring quotes. */
|
|
60
|
+
function splitSegments(input) {
|
|
61
|
+
const out = [];
|
|
62
|
+
let cur = '';
|
|
63
|
+
let q = null;
|
|
64
|
+
let esc = false;
|
|
65
|
+
for (let i = 0; i < input.length; i++) {
|
|
66
|
+
const c = input[i];
|
|
67
|
+
if (esc) { cur += c; esc = false; continue; }
|
|
68
|
+
if (c === '\\' && q !== "'") { cur += c; esc = true; continue; }
|
|
69
|
+
if (q) { cur += c; if (c === q) q = null; continue; }
|
|
70
|
+
if (c === '"' || c === "'") { q = c; cur += c; continue; }
|
|
71
|
+
if (c === '|' || c === '&' || c === ';' || c === '\n') {
|
|
72
|
+
let op = c;
|
|
73
|
+
if ((c === '|' || c === '&') && input[i + 1] === c) { op = c + c; i++; }
|
|
74
|
+
out.push(cur, op);
|
|
75
|
+
cur = '';
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
cur += c;
|
|
79
|
+
}
|
|
80
|
+
out.push(cur);
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Describe redirections found in a raw segment. */
|
|
85
|
+
function redirectNotes(seg) {
|
|
86
|
+
const notes = [];
|
|
87
|
+
if (/2>&1|&>/.test(seg)) notes.push('合并错误输出');
|
|
88
|
+
if (/>\s*\/dev\/null/.test(seg)) notes.push('丢弃输出');
|
|
89
|
+
else {
|
|
90
|
+
const append = /(?:^|[^>])>>\s*([^\s|&;]+)/.exec(seg);
|
|
91
|
+
const write = /(?:^|[^>])>\s*([^\s|&;]+)/.exec(seg);
|
|
92
|
+
if (append) notes.push(`追加输出到 ${append[1]}`);
|
|
93
|
+
else if (write && write[1] !== '/dev/null') notes.push(`输出重定向到 ${write[1]}`);
|
|
94
|
+
}
|
|
95
|
+
const input = /(?:^|\s)<\s*([^\s|&;]+)/.exec(seg);
|
|
96
|
+
if (input) notes.push(`输入来自 ${input[1]}`);
|
|
97
|
+
return notes;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Explain one command segment. handled: true | 'partial' | false. */
|
|
101
|
+
function explainSegment(seg) {
|
|
102
|
+
const words = tokenize(seg);
|
|
103
|
+
if (words.length === 0) return { handled: true, text: '' };
|
|
104
|
+
const { notes, rest } = unwrap(words);
|
|
105
|
+
if (rest.length === 0) return { handled: true, text: notes.join(',') };
|
|
106
|
+
let name = rest[0];
|
|
107
|
+
if (name.includes('/')) name = name.slice(name.lastIndexOf('/') + 1);
|
|
108
|
+
if (!/^[A-Za-z_][A-Za-z0-9_.+-]*$/.test(name)) return { handled: false };
|
|
109
|
+
const entry = COMMANDS[name];
|
|
110
|
+
if (!entry) return { handled: false };
|
|
111
|
+
const flags = entry.f || {};
|
|
112
|
+
const descs = [];
|
|
113
|
+
let unknown = false;
|
|
114
|
+
let positionalOnly = false;
|
|
115
|
+
for (const w of rest.slice(1)) {
|
|
116
|
+
if (positionalOnly) break;
|
|
117
|
+
if (w === '--') { positionalOnly = true; continue; }
|
|
118
|
+
if (/^(?:>|<|>>)/.test(w) || /^\d*>&/.test(w)) continue;
|
|
119
|
+
if (w.startsWith('--')) {
|
|
120
|
+
const key = w.split('=')[0];
|
|
121
|
+
if (flags[key]) descs.push(flags[key]);
|
|
122
|
+
else unknown = true;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (w.startsWith('-') && w.length > 1 && !/^-\d/.test(w)) {
|
|
126
|
+
if (flags[w]) { descs.push(flags[w]); continue; }
|
|
127
|
+
let allKnown = true;
|
|
128
|
+
for (const ch of w.slice(1)) {
|
|
129
|
+
if (flags['-' + ch]) descs.push(flags['-' + ch]);
|
|
130
|
+
else allKnown = false;
|
|
131
|
+
}
|
|
132
|
+
if (!allKnown) unknown = true;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const parts = [];
|
|
137
|
+
if (notes.length) parts.push(notes.join(','));
|
|
138
|
+
parts.push(entry.d + (descs.length ? ':' + [...new Set(descs)].join(',') : ''));
|
|
139
|
+
const redir = redirectNotes(seg);
|
|
140
|
+
if (redir.length) parts.push(redir.join(','));
|
|
141
|
+
return { handled: unknown ? 'partial' : true, text: parts.join(','), danger: entry.danger };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const OP_TEXT = { '|': ';输出交给', '&&': ';成功后执行', '||': ';失败时执行', ';': ';接着执行', '&': '(后台运行)' };
|
|
145
|
+
|
|
146
|
+
/** Explain a full command line (pipes / lists / redirects). */
|
|
147
|
+
export function explainCommand(input) {
|
|
148
|
+
const parts = splitSegments(input);
|
|
149
|
+
const texts = [];
|
|
150
|
+
const dangers = [];
|
|
151
|
+
let partial = false;
|
|
152
|
+
let pendingOp = null;
|
|
153
|
+
for (let i = 0; i < parts.length; i++) {
|
|
154
|
+
if (i % 2 === 1) { pendingOp = parts[i]; continue; }
|
|
155
|
+
const seg = parts[i].trim();
|
|
156
|
+
if (!seg) { pendingOp = null; continue; }
|
|
157
|
+
const r = explainSegment(seg);
|
|
158
|
+
if (r.handled === false) return { handled: false };
|
|
159
|
+
if (r.handled === 'partial') partial = true;
|
|
160
|
+
if (r.danger) dangers.push(r.danger);
|
|
161
|
+
let text = r.text;
|
|
162
|
+
if (texts.length && pendingOp && OP_TEXT[pendingOp]) {
|
|
163
|
+
text = pendingOp === '&' ? text + OP_TEXT['&'] : OP_TEXT[pendingOp] + ' ' + text;
|
|
164
|
+
} else if (pendingOp === '&') {
|
|
165
|
+
text += OP_TEXT['&'];
|
|
166
|
+
}
|
|
167
|
+
if (text) texts.push(text);
|
|
168
|
+
pendingOp = null;
|
|
169
|
+
}
|
|
170
|
+
if (!texts.length) return { handled: false };
|
|
171
|
+
for (const rule of DANGER_RULES) {
|
|
172
|
+
try {
|
|
173
|
+
if (new RegExp(rule.re, 'i').test(input)) dangers.push(rule.warn);
|
|
174
|
+
} catch { /* skip malformed data rule */ }
|
|
175
|
+
}
|
|
176
|
+
const warning = [...new Set(dangers)].join(';');
|
|
177
|
+
return {
|
|
178
|
+
handled: partial ? 'partial' : true,
|
|
179
|
+
kind: 'explain',
|
|
180
|
+
command: input,
|
|
181
|
+
explanation: cap(texts.join(''), MAX_EXPLAIN),
|
|
182
|
+
...(warning ? { warning: cap(warning, MAX_WARN) } : {}),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** First matching natural-language rule wins. */
|
|
187
|
+
export function generateNL(input) {
|
|
188
|
+
for (const rule of NL_RULES) {
|
|
189
|
+
const m = rule.re.exec(input);
|
|
190
|
+
if (!m) continue;
|
|
191
|
+
let cmd;
|
|
192
|
+
try {
|
|
193
|
+
cmd = typeof rule.cmd === 'function' ? rule.cmd(m) : rule.cmd;
|
|
194
|
+
} catch { continue; }
|
|
195
|
+
if (typeof cmd !== 'string' || !cmd.trim()) continue;
|
|
196
|
+
return {
|
|
197
|
+
handled: true,
|
|
198
|
+
kind: 'generate',
|
|
199
|
+
command: cmd.trim(),
|
|
200
|
+
explanation: rule.note || '',
|
|
201
|
+
...(rule.warn ? { warning: rule.warn } : {}),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return { handled: false };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Classify input: 'command' | 'natural' | 'auto'. */
|
|
208
|
+
export function detectIntent(input) {
|
|
209
|
+
const trimmed = input.trim();
|
|
210
|
+
if (!trimmed) return null;
|
|
211
|
+
const first = trimmed.split(/\s+/)[0];
|
|
212
|
+
const base = first.includes('/') ? first.slice(first.lastIndexOf('/') + 1) : first;
|
|
213
|
+
if (COMMANDS[base] || base === 'sudo') return 'command';
|
|
214
|
+
if (CJK.test(trimmed)) return NL_HINT.test(trimmed) ? 'natural' : 'natural';
|
|
215
|
+
if (SHELL_META.test(trimmed) || /\s--?[A-Za-z]/.test(trimmed)) return 'command';
|
|
216
|
+
if (/^\.{1,2}\//.test(trimmed) || /^~\//.test(trimmed)) return 'command';
|
|
217
|
+
if (/^[A-Za-z_][A-Za-z0-9_.+-]*$/.test(trimmed)) return 'auto';
|
|
218
|
+
return 'auto';
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Local-first pipeline with injected AI fallback. */
|
|
222
|
+
export function createPipeline({ ai }) {
|
|
223
|
+
return async function run(raw) {
|
|
224
|
+
const input = String(raw ?? '').replace(/[\r\n]+/g, ' ').trim().slice(0, 500);
|
|
225
|
+
if (!input) return { ok: false, code: 'empty', message: '请输入内容' };
|
|
226
|
+
const intent = detectIntent(input);
|
|
227
|
+
let partial = null;
|
|
228
|
+
if (intent === 'command' || intent === 'auto') {
|
|
229
|
+
const r = explainCommand(input);
|
|
230
|
+
if (r.handled === true) return { ok: true, source: 'local', ...r };
|
|
231
|
+
if (r.handled === 'partial') partial = r;
|
|
232
|
+
}
|
|
233
|
+
if (intent === 'natural' || intent === 'auto') {
|
|
234
|
+
const r = generateNL(input);
|
|
235
|
+
if (r.handled) return { ok: true, source: 'local', ...r };
|
|
236
|
+
}
|
|
237
|
+
const res = await ai.query(input, intent);
|
|
238
|
+
if (res.ok) return res;
|
|
239
|
+
if (partial) {
|
|
240
|
+
return { ok: true, source: 'local', ...partial, explanation: cap(partial.explanation + '(部分参数未收录,仅供参考)', MAX_EXPLAIN) };
|
|
241
|
+
}
|
|
242
|
+
return res;
|
|
243
|
+
};
|
|
244
|
+
}
|