From aa1f592bf39846e243038829c3926b642317b3b5 Mon Sep 17 00:00:00 2001 From: Odboy Date: Tue, 3 Nov 2026 21:28:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20proc.list/user.lis?= =?UTF-8?q?t/pkg.list=20=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit proc.list 列出所有进程(ps aux/tasklist) user.list 列出系统用户(getent passwd/net user) pkg.list 列出已安装软件包(dpkg/rpm/apk/brew/winget) --- README.pkg.md | 21 +++++++- README.proc.md | 9 ++++ README.user.md | 9 ++++ internal/executor/builtin.go | 3 ++ internal/executor/pkglist.go | 77 ++++++++++++++++++++++++++++++ internal/executor/proclist.go | 26 ++++++++++ internal/executor/userlist.go | 51 ++++++++++++++++++++ internal/registry/builtin.go | 24 ++++++++++ internal/registry/registry_test.go | 6 +-- 9 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 internal/executor/pkglist.go create mode 100644 internal/executor/proclist.go create mode 100644 internal/executor/userlist.go diff --git a/README.pkg.md b/README.pkg.md index fa10d3b..fe6ec8d 100644 --- a/README.pkg.md +++ b/README.pkg.md @@ -2,12 +2,29 @@ > 返回 [README.md](README.md) -刷新系统包管理器的软件源索引。 +刷新系统包管理器的软件源索引,或列出已安装的软件包。 ```bash -kopsc pkg refreshindex # 刷新包管理器索引(dnf/apt/apk/brew/winget,按平台自动选) +kopsc pkg list # 列出已安装的软件包 +kopsc pkg refreshindex # 刷新包管理器索引(dnf/apt/apk/brew/winget,按平台自动选) ``` +## 列出已安装的软件包(pkg.list) + +```bash +kopsc pkg list +``` + +列出系统中已安装的软件包。 + +| 平台 | 实际执行 | +| --- | --- | +| Linux(Debian/Ubuntu) | `dpkg -l` | +| Linux(CentOS/RHEL/Fedora) | `rpm -qa` | +| Linux(Alpine) | `apk list --installed` | +| macOS | `brew list` | +| Windows | `winget list` | + ## 刷新软件源索引(pkg.refreshindex) `kopsc pkg refreshindex` 刷新本机包管理器的软件源索引,**只更新索引,不升级也不安装任何软件包**。 diff --git a/README.proc.md b/README.proc.md index edcb8aa..d834018 100644 --- a/README.proc.md +++ b/README.proc.md @@ -6,6 +6,7 @@ 还能按资源占用排序查看进程、按名称终止进程、查看进程树。 ```bash +kopsc proc list # 列出所有进程 kopsc proc nohup ./server # 后台运行命令,输出写日志 kopsc proc wait nginx # 等 nginx 退出后返回 kopsc proc topmem # 内存占用前 10 的进程 @@ -14,6 +15,14 @@ kopsc proc killname nginx --yes # 终止名为 nginx 的进程 kopsc proc tree # 查看进程树 ``` +## 列出所有进程(proc.list) + +```bash +kopsc proc list +``` + +列出系统中所有正在运行的进程。Linux/macOS 使用 `ps aux`,Windows 使用 `tasklist`。 + ## 后台运行(proc.nohup) `kopsc proc nohup <命令> [参数...]` 等价于 `nohup <命令> > output.log 2>&1 &`: diff --git a/README.user.md b/README.user.md index 41714ea..7c35ca3 100644 --- a/README.user.md +++ b/README.user.md @@ -6,12 +6,21 @@ | 命令 | 用途 | 实际执行 | | --- | --- | --- | +| `kopsc user list` | 列出系统用户 | Linux/macOS: `getent passwd` 或 `/etc/passwd`
Windows: `net user` | | `kopsc user grant <用户名>` | 授予用户 root/sudo 权限 | Linux: `usermod -aG wheel/sudo <用户名>`
macOS: `dseditgroup -o edit -t user -a <用户名> admin`
Windows: `net localgroup Administrators <用户名> /add` | | `kopsc user revoke <用户名>` | 移除用户的 root/sudo 权限 | Linux: `gpasswd -d <用户名> wheel/sudo`
macOS: `dseditgroup -o edit -t user -d <用户名> admin`
Windows: `net localgroup Administrators <用户名> /delete` | | `kopsc user info [用户名]` | 查看用户详细信息 | Linux/macOS: `id` + `/etc/passwd` + `groups`
Windows: `net user` | ## 用法 +### 列出系统用户 + +```bash +kopsc user list +``` + +列出系统中所有用户账户。Linux/macOS 优先使用 `getent passwd`,回退到读取 `/etc/passwd`;Windows 使用 `net user`。 + ### 授予用户 root/sudo 权限 ```bash diff --git a/internal/executor/builtin.go b/internal/executor/builtin.go index 94211b4..5427f7d 100644 --- a/internal/executor/builtin.go +++ b/internal/executor/builtin.go @@ -70,7 +70,9 @@ var builtins = map[string]Builtin{ "net.ports": runNetPorts, "net.speed": runNetSpeed, "net.trace": runNetTrace, + "pkg.list": runPkgList, "proc.killname": runProcKillName, + "proc.list": runProcList, "proc.nohup": runNohup, "proc.topcpu": runProcTopCPU, "proc.topmem": runProcTopMem, @@ -84,6 +86,7 @@ var builtins = map[string]Builtin{ "sysinfo": runSysInfo, "user.grant": runUserGrant, "user.info": runUserInfo, + "user.list": runUserList, "user.revoke": runUserRevoke, } diff --git a/internal/executor/pkglist.go b/internal/executor/pkglist.go new file mode 100644 index 0000000..089e9b7 --- /dev/null +++ b/internal/executor/pkglist.go @@ -0,0 +1,77 @@ +package executor + +import ( + "context" + "fmt" + "os/exec" + "runtime" + "strings" + + "gitea.odboy.cn/odboy/kenaito-kopsc/internal/platform" +) + +// runPkgList implements `kopsc pkg list`: list installed packages. +func runPkgList(ctx context.Context, req BuiltinRequest) error { + switch runtime.GOOS { + case "linux": + return pkgListLinux(ctx, req) + case "darwin": + cmd := exec.CommandContext(ctx, "brew", "list") + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + case "windows": + cmd := exec.CommandContext(ctx, "winget", "list") + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + default: + return fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) + } +} + +func pkgListLinux(ctx context.Context, req BuiltinRequest) error { + info := platform.System().Detect() + + // Debian/Ubuntu: dpkg -l + if distroLikeContains(info, "debian", "ubuntu") { + cmd := exec.CommandContext(ctx, "dpkg", "-l") + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + // CentOS/RHEL/Fedora: rpm -qa + if distroLikeContains(info, "rhel", "fedora") || info.Distro == "centos" { + cmd := exec.CommandContext(ctx, "rpm", "-qa", "--qf", "%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n") + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + // Alpine: apk list --installed + if info.Distro == "alpine" { + cmd := exec.CommandContext(ctx, "apk", "list", "--installed") + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + return fmt.Errorf("不支持的 Linux 发行版: %s", info.Distro) +} + +func distroLikeContains(info platform.Info, values ...string) bool { + all := make([]string, 0, 1+len(info.DistroLike)) + if info.Distro != "" { + all = append(all, info.Distro) + } + all = append(all, info.DistroLike...) + for _, a := range all { + for _, v := range values { + if strings.EqualFold(a, v) { + return true + } + } + } + return false +} diff --git a/internal/executor/proclist.go b/internal/executor/proclist.go new file mode 100644 index 0000000..05a9b11 --- /dev/null +++ b/internal/executor/proclist.go @@ -0,0 +1,26 @@ +package executor + +import ( + "context" + "fmt" + "os/exec" + "runtime" +) + +// runProcList implements `kopsc proc list`: list all processes. +func runProcList(ctx context.Context, req BuiltinRequest) error { + switch runtime.GOOS { + case "linux", "darwin": + cmd := exec.CommandContext(ctx, "ps", "aux") + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + case "windows": + cmd := exec.CommandContext(ctx, "tasklist") + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + default: + return fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) + } +} diff --git a/internal/executor/userlist.go b/internal/executor/userlist.go new file mode 100644 index 0000000..e637492 --- /dev/null +++ b/internal/executor/userlist.go @@ -0,0 +1,51 @@ +package executor + +import ( + "context" + "fmt" + "os/exec" + "runtime" + "strings" +) + +// runUserList implements `kopsc user list`: list all users. +func runUserList(ctx context.Context, req BuiltinRequest) error { + switch runtime.GOOS { + case "linux", "darwin": + return userListUnix(ctx, req) + case "windows": + cmd := exec.CommandContext(ctx, "net", "user") + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + default: + return fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) + } +} + +func userListUnix(ctx context.Context, req BuiltinRequest) error { + // Try getent first (more portable), fall back to reading /etc/passwd + if path, err := exec.LookPath("getent"); err == nil { + cmd := exec.CommandContext(ctx, path, "passwd") + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + // Fall back to /etc/passwd + out, err := exec.CommandContext(ctx, "cat", "/etc/passwd").Output() + if err != nil { + return fmt.Errorf("读取用户列表失败: %w", err) + } + fmt.Fprintln(req.Stdout, "用户名:UID:GID:描述:家目录:Shell") + for _, line := range strings.Split(string(out), "\n") { + if line == "" { + continue + } + fields := strings.Split(line, ":") + if len(fields) >= 7 { + fmt.Fprintf(req.Stdout, "%s:%s:%s:%s:%s:%s\n", + fields[0], fields[2], fields[3], fields[4], fields[5], fields[6]) + } + } + return nil +} diff --git a/internal/registry/builtin.go b/internal/registry/builtin.go index d711e96..e4d1b66 100644 --- a/internal/registry/builtin.go +++ b/internal/registry/builtin.go @@ -513,6 +513,15 @@ func Builtin() *Registry { }, }, }, + { + ID: "pkg.list", + Group: "pkg", + Summary: "列出已安装的软件包", + Action: "列出系统中已安装的软件包。" + + "Linux: dpkg -l(Debian/Ubuntu)/ rpm -qa(CentOS/RHEL)/ apk list(Alpine);" + + "macOS: brew list;Windows: winget list", + Variants: threePlatformBuiltins("pkg.list"), + }, { ID: "pkg.refreshindex", Group: "pkg", @@ -551,6 +560,14 @@ func Builtin() *Registry { }, }, }, + { + ID: "user.list", + Group: "user", + Summary: "列出系统用户", + Action: "列出系统中所有用户账户。" + + "Linux/macOS: getent passwd 或 /etc/passwd;Windows: net user", + Variants: threePlatformBuiltins("user.list"), + }, { ID: "user.grant", Group: "user", @@ -720,6 +737,13 @@ func Builtin() *Registry { }, // ----- proc additions ----- + { + ID: "proc.list", + Group: "proc", + Summary: "列出所有进程", + Action: "列出系统中所有正在运行的进程。Linux/macOS: ps aux;Windows: tasklist", + Variants: threePlatformBuiltins("proc.list"), + }, { ID: "proc.topmem", Group: "proc", diff --git a/internal/registry/registry_test.go b/internal/registry/registry_test.go index d82e5bb..689dd98 100644 --- a/internal/registry/registry_test.go +++ b/internal/registry/registry_test.go @@ -25,13 +25,13 @@ func TestBuiltinIDsStable(t *testing.T) { "docker.prunebuilder", "docker.prunevolumes", "docker.clearall", "docker.compose.up", "docker.compose.down", "docker.compose.ps", "docker.compose.logs", "diagnose", - "disk.usage", "net.pids", "net.ports", "proc.nohup", "proc.wait", "java.run", "git.retime", "pkg.refreshindex", - "user.grant", "user.revoke", + "disk.usage", "net.pids", "net.ports", "proc.nohup", "proc.wait", "java.run", "git.retime", "pkg.list", "pkg.refreshindex", + "user.list", "user.grant", "user.revoke", "file.findbig", "file.findrecent", "file.findname", "svc.list", "svc.status", "svc.enable", "svc.disable", "svc.logs", "archive.extract", "sysinfo", - "proc.topmem", "proc.topcpu", "proc.killname", + "proc.list", "proc.topmem", "proc.topcpu", "proc.killname", "net.ping", "net.trace", "net.dns", "net.curl", "log.list", "log.search", "log.last", "fw.status", "fw.allow", "fw.deny",