aiagent.sh — 100% POSIX-sh 自然语言运维 Agent
一行英文句子 = 一条运维命令。不用背参数,不用记 flag。
aiagent.sh 是一个纯 /bin/sh 实现的轻量级"AI Agent"。它不需要 Python、不需要 node、不需要任何运行时——单文件、零依赖,却能把你输入的自然英语句子解析成真实的运维操作。
$ ./aiagent.sh
aiagent> please show disk usage
[INFO] Disk usage:
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 100G 42G 58G 42% /
aiagent> what is the uptime
[INFO] System uptime:
14:32:11 up 12 days, 3:17, 2 users, load average: 0.12, 0.08, 0.01
aiagent> check port 8080
[INFO] Checking port 8080 ...
[OK] Port 8080 is IN USE
✨ 核心特性
| 特性 | 说明 |
|---|---|
| 🗣️ 自然语言输入 | 接受完整英文句子,不需要任何特殊语法 |
| 🧠 意图识别 | 自动提取动词、名词、路径、端口、服务名 |
| 🔄 同义词归一 | show/display/list → 统一处理,kill/stop/terminate → 统一处理 |
| 🎯 名词推断动作 | 只说 uptime 也能理解成"show uptime" |
| 🔒 安全确认 | 所有破坏性操作(删除、杀进程、装包)强制 y/N 二次确认 |
| 🛡️ 零 eval 注入 | 没有任何字符串拼接执行,包管理器直接调用 |
| ⚙️ 自动适配环境 | 自动检测 systemctl/service、ss/netstat、apt/dnf/yum/apk/pacman |
| 🧩 可扩展 | 每个 do_xxx() 函数独立,新增操作只需加一个 case 分支和一个函数 |
| 📦 单文件分发 | 约 1050 行,直接 cp 到目标机就能跑 |
🚀 快速上手
1. 获取脚本
# 从git仓库获取
git clone https://github.com/CancerXiaoAi/shell-ai.git
git clone https://git.cancerai.top/cancerai/shell-ai.git
2. 两种使用方式
# 方式 A:交互式 REPL(推荐日常使用)
./aiagent.sh
# 方式 B:一行命令模式(适合脚本/CI)
./aiagent.sh "please check port 443"
./aiagent.sh "what is the kernel version"
./aiagent.sh "health check"
3. 最简示例
# 系统一句话
./aiagent.sh uptime # 直接说名词就行
./aiagent.sh disk
./aiagent.sh health
# 完整句子也没问题
./aiagent.sh "please help me show memory usage"
./aiagent.sh "could you ping google.com for me"
./aiagent.sh "i want to restart nginx"
📖 完整命令参考
💡 语法约定
脚本对输入的容忍度极高。以下写法全部等价:
please help me check disk usage
help me check disk
check disk
disk
规则:
please、help me、to、a、the、can you、would you等纯语法词全部自动忽略- 只带名词(如
uptime)会被自动推断为"show + 该名词" - 只带动词加短语(如
check port 80)直接路由
🖥️ 系统信息 — System Info
| 输入示例 | 实际调用 | 说明 |
|---|---|---|
show disk usage / disk |
df -h |
磁盘使用情况 |
check memory / memory / ram |
/proc/meminfo 或 free -h |
内存占用 |
check cpu load / cpu / load |
/proc/loadavg |
CPU 负载 |
what is the uptime / uptime |
uptime |
系统运行时长 |
show kernel version / version |
/etc/os-release + uname |
OS 和内核版本 |
show listening ports |
ss -tulnp 或 netstat -tulnp |
监听端口 |
who is logged in / show users |
who |
当前登录用户 |
health check / check |
一键跑 uptime + CPU + 内存 + 磁盘 | 健康检查 |
📂 文件操作 — Files
| 输入示例 | 实际调用 | 说明 |
|---|---|---|
list files in /var/log |
ls -lah /var/log |
列出目录 |
show me content of /etc/hosts |
ls /etc/hosts |
查看文件 |
find files named *.log in /tmp |
find /tmp -type f -name "*.log" |
查找文件 |
find process nginx |
`ps aux | grep nginx` |
create directory /data |
mkdir -p /data |
创建目录 |
create file /tmp/hello.txt |
: > /tmp/hello.txt |
创建空文件 |
copy /etc/hosts /tmp/hosts.bak |
cp -r/-f |
自动判断文件/目录复制 |
move /tmp/a.log /var/log/ |
mv -f |
移动/重命名 |
⚠️ 破坏性操作 — Destructive(强制 y/N 确认)
| 输入示例 | 实际调用 | 说明 |
|---|---|---|
please remove /tmp/cache |
rm -rf(确认后) |
递归删目录 |
delete file /tmp/bad.log |
rm -f(确认后) |
删除文件 |
clean old log files in /var/log |
find -delete(确认后) |
清理日志 |
kill process nginx |
kill + PID 列表(确认后) |
按名字杀进程 |
kill the process on port 8080 |
先 lsof/ss 找 PID(确认后) | 按端口杀进程 |
stop nginx |
systemctl stop(确认后) |
停服务 |
🔌 服务管理 — Services
| 输入示例 | 实际调用 | 说明 |
|---|---|---|
check status of sshd |
systemctl status |
查看服务状态 |
start docker service |
systemctl start |
启动服务 |
restart nginx |
systemctl restart |
重启服务 |
nginx |
自动识别服务名 → 查状态 | 裸服务名默认查状态 |
🌐 网络 — Network
| 输入示例 | 实际调用 | 说明 |
|---|---|---|
check port 443 / port 443 |
ss/netstat/nc |
检查端口监听状态 |
ping google.com |
ping -c 3 -W 2 |
连通性测试(3 包) |
show listening ports |
ss -tulnp |
所有监听端口 |
📦 包管理 — Packages
| 输入示例 | 实际调用 | 说明 |
|---|---|---|
please install package htop |
自动检测 apt-get/dnf/yum/apk/pacman 并调用 |
安装系统包(确认后) |
📜 日志 — Logs
| 输入示例 | 实际调用 | 说明 |
|---|---|---|
tail /var/log/syslog |
tail -30 |
直接路径 |
tail nginx log |
自动匹配 /var/log/nginx/access.log |
按服务名猜路径 |
follow docker log |
glob /var/log/*docker* |
模糊匹配 |
🎛️ 其他
| 输入 | 说明 |
|---|---|
help |
打印帮助手册 |
quit / exit / bye |
退出 REPL |
🧠 自然语言解析原理
整个解析管线分为 5 层,每一层都只使用 POSIX sh 原语实现:
用户输入:please help me check port 8080
│
▼
┌─────────────────────────────────┐
│ 第 1 层:strip_fillers() │
│ 丢弃纯语法词:please, help, me │
└─────────────────────────────────┘
│ 得到:check port 8080
▼
┌─────────────────────────────────┐
│ 第 2 层:跳过引导词 │
│ 跳过开头的 help/what/can 等客气词│
└─────────────────────────────────┘
│ 得到:check port 8080
▼
┌─────────────────────────────────┐
│ 第 3 层:canonical_verb() │
│ 动词→同义词归一 │
│ 名词→推断动作(health→check) │
└─────────────────────────────────┘
│ verb=check, phrase="port 8080"
▼
┌─────────────────────────────────┐
│ 第 4 层:dispatch() 一级匹配 │
│ case "$phrase" in *port*) │
│ do_check_port; _matched=1 ;; │
└─────────────────────────────────┘
│
▼
┌─────────────────────────────────┐
│ 第 5 层:do_check_port() │
│ 从短语中提取 "8080" │
│ 依次尝试 ss → netstat → nc │
│ 输出 [OK]/[WARN] 状态 │
└─────────────────────────────────┘
动词同义词映射(canonical_verb)
show ← show, display, list, print, tell, what, reveal, dump
check ← check, monitor, verify, inspect, diagnose
find ← find, locate, search, lookup, track
remove← remove, delete, erase, rm, wipe, cleanup, clean
kill ← kill, stop, terminate, shutdown, halt
start ← start, launch, run, begin, enable
...
名词 → 推断动作
uptime, disk, memory, cpu, version, port, process ... → 自动当作 show
health, status, connection, reachability → 自动当作 check
三级 fallback 匹配机制
每个规范动词的路由都有三级兜底:
- 一级关键词匹配:
*disk*→ do_show_disk,*port*→ do_check_port - 二级兜底:短语是纯数字 → 当作端口号;短语含已知服务名 → do_service_status
- 三级兜底:
check空短语 → do_health_check;其他 → 提示用户重述
🔒 安全设计
强制二次确认
以下操作必须输入 y 或 yes 才会继续,其他任何输入都视为取消:
- 删除目录/文件(
remove,delete) - 杀进程(
kill) - 停服务(
stop service) - 安装系统包(
install)
[CONFIRM] Recursively remove directory '/tmp/cache' ? (y/N):
零 eval 注入
整个脚本没有任何 eval 调用。包管理器的调用采用直接分支方式:
if command -v apt-get >/dev/null 2>&1; then
apt-get install -y -- "$_pkg" # 直接调用,参数安全引用
elif command -v dnf >/dev/null 2>&1; then
dnf install -y -- "$_pkg"
...
路径安全
rm -rf、mv、cp 等危险操作都使用了 -- 分隔符,防止路径以 - 开头被解释为选项。
信号处理
REPL 模式下按 Ctrl+C 会优雅退出,不会留下终端异常状态:
trap 'echo; printf "Bye.\n"; exit 130' INT TERM
🏗️ 架构总览
aiagent.sh (~1050 lines, 单文件)
├── 辅助函数层
│ ├── info() / warn() / error() / success() # 带颜色的日志输出
│ └── confirm() # y/N 安全确认
│
├── 解析层(第 1–3 层)
│ ├── strip_fillers() # 丢弃纯语法词
│ ├── canonical_verb() # 同义词归一 + 名词推断
│ ├── _extract_path() # 从短语中提取路径
│ ├── _extract_svcname() # 从短语中提取服务名
│ └── _SERVICES_RE # 已知服务名正则
│
├── 路由层(第 4 层)
│ └── dispatch() # 大 case 分支,三级 fallback
│
├── 执行层(第 5 层)
│ ├── do_show_disk / _memory / _cpu / _uptime / _version / ...
│ ├── do_check_port / do_ping_host / do_service_status / do_health_check
│ ├── do_find_process / do_find_file
│ ├── do_remove_dir / _file / _log
│ ├── do_kill_process / do_kill_by_port
│ ├── do_service_start / _restart / _stop
│ ├── do_create_dir / _file
│ ├── do_copy_path / do_move_path
│ ├── do_install_pkg
│ └── do_tail_log
│
├── REPL 层
│ ├── run_one() # 单次命令处理管线
│ └── repl() # 交互式循环
│
└── 入口
└── main() # 分交互式/一行模式
依赖关系图
main() ─→ repl() 或 run_one()
│
▼
dispatch()
│
┌─────────┼─────────────┬──────────┬────────────┐
▼ ▼ ▼ ▼ ▼
show() check() find() remove() install()
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
do_show_* do_check_* do_find_* do_remove_* do_install_pkg
│
▼
confirm() ←── 所有 destructive 函数必经
⚙️ 运行要求
最低要求
| 项目 | 要求 |
|---|---|
| Shell 解释器 | /bin/sh(POSIX sh,任何实现均可:dash / busybox / bash --posix) |
| 操作系统 | Linux(主要目标);macOS 可读但部分功能受限(无 systemctl/ss) |
| 权限 | 普通用户即可运行,执行破坏性/管理类命令时需要相应权限 |
可选依赖(根据操作自动探测)
| 操作 | 依赖(择一) |
|---|---|
| 磁盘/内存/CPU | df, /proc/meminfo 或 free, /proc/loadavg |
| 服务管理 | systemctl 或 service |
| 端口检查 | ss / netstat / nc |
| 进程查找 | ps, pgrep(可选) |
| 进程/端口杀 | pgrep, lsof, fuser(择一) |
| 网络 | ping |
| 文件查找 | find |
| 包安装 | apt-get / dnf / yum / apk / pacman(择一) |
跨包管理器支持
| 发行版 | 自动使用 |
|---|---|
| Debian / Ubuntu | apt-get |
| RHEL 8+ / Fedora / CentOS 8+ | dnf |
| RHEL 7 / CentOS 7 | yum |
| Alpine | apk |
| Arch / Manjaro | pacman |
⚡ 性能
解析管线全部使用 POSIX sh 内建实现(case / for / if / read / printf),不 fork 任何外部进程——除了 grep -qE 和 awk 在少数 fallback 分支里会被调用。整个"strip → canonical → dispatch → route"管线的纯解析开销可以忽略不计,实际耗时主要来自底层命令本身(如 df -h、ps aux、systemctl 等)。
🧪 快速验证
在 Docker 容器里跑一下(无需在本机安装任何东西):
# Debian
docker run --rm -it -v $(pwd)/aiagent.sh:/aiagent.sh debian:latest \
sh -c 'chmod +x /aiagent.sh && /aiagent.sh "health check"'
# Alpine
docker run --rm -it -v $(pwd)/aiagent.sh:/aiagent.sh alpine:latest \
sh -c 'chmod +x /aiagent.sh && /aiagent.sh "check port 22"'
# CentOS / Rocky / AlmaLinux
docker run --rm -it -v $(pwd)/aiagent.sh:/aiagent.sh rocky:9 \
sh -c 'chmod +x /aiagent.sh && /aiagent.sh "restart sshd"'
🛠️ 扩展指南
想新增一个操作(比如"备份数据库")?三个步骤:
步骤 1:加一个规范动词映射(如果是新动词)
canonical_verb() {
...
backup|dump) echo "backup" ;;
...
}
步骤 2:在 dispatch() 的 case 分支里加路由
dispatch() {
...
backup)
do_backup_db "$phrase" ;;
...
}
步骤 3:实现 do_backup_db() 函数
do_backup_db() {
_db=""
for _tok in $1; do
case "$_tok" in mysql|postgres|redis|mongodb) _db="$_tok" ;; esac
done
[ -z "$_db" ] && { error "No DB type. Example: 'backup mysql'"; return 1; }
confirm "Backup $_db ?" || return 1
# 实际备份逻辑
case "$_db" in
mysql) mysqldump ... ;;
postgres) pg_dump ... ;;
...
esac
}
完成。现在 ./aiagent.sh "please backup mysql database" 就能工作了。
🐛 已知限制
| 限制 | 说明 |
|---|---|
| 只能识别英文 | 整个关键词库是英语 hardcode 的,不支持中文 |
| 正则只支持 POSIX ERE | 不支持 PCRE(但对运维场景已足够) |
| 交互式 REPL 不支持命令历史 | POSIX sh 的 read 没有 readline;可以通过 rlwrap ./aiagent.sh 获得历史 |
端口号从短语提取用的是 [0-9]* |
如果句子里有多个数字,会取最后一个(对"check port 80 on server 192.168.1.1"这种会取 1) |
| macOS 功能受限 | 没有 systemctl/ss//proc/*,部分操作会降级或报依赖缺失 |
| 包管理器自动检测 | 只是检测命令是否存在,不检查是否真的可用(例如在 chroot 里) |
📄 License
MIT License. 复制、修改、商用均自由,唯一要求保留版权声明。
🙏 致谢
- POSIX 标准委员会:没有你们就没有可移植的 shell
- 所有写出漂亮运维命令的前辈:你们的
df -h、ps aux、ss -tulnp是这个项目的基石