feat: 1.新增 cp、pwd、tail、wget、kill、top命令支持
2.新增 README.md 文件,提供项目说明和使用指南
This commit is contained in:
@@ -8,4 +8,7 @@ edition = "2021"
|
||||
chrono = "0.4.38"
|
||||
colored = "2.1.0"
|
||||
filetime = "0.2.25"
|
||||
regex = "1.11.0"
|
||||
reqwest = { version = "0.12.8", features = ["blocking", "rustls-tls"] }
|
||||
sysinfo = "0.32.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
134
README.md
Normal file
134
README.md
Normal file
@@ -0,0 +1,134 @@
|
||||
|
||||
# WinShell
|
||||
|
||||
WinShell 是一个使用 Rust 实现的命令行工具集合,旨在提供在 Windows 环境下类似于 Linux 系统常用命令的功能。这些命令包括 `ls`、`mv`、`mkdir`、`rm`、`cat`、`cp`、`tail`、`top` 等,方便在 Windows 平台上执行类似 Unix 风格的命令操作。
|
||||
|
||||
## 项目结构
|
||||
|
||||
项目按照不同类型的命令进行分类,使用子目录来组织各类操作。目录结构如下:
|
||||
|
||||
```
|
||||
WinShell/
|
||||
├── src/
|
||||
│ ├── commands/
|
||||
│ │ ├── directory_ops/ # 文件目录相关命令
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── mkdir.rs
|
||||
│ │ ├── file_ops/ # 文件操作相关命令
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── cp.rs
|
||||
│ │ │ ├── ls.rs
|
||||
│ │ │ ├── mv.rs
|
||||
│ │ │ ├── mkdir.rs
|
||||
│ │ │ ├── rm.rs
|
||||
│ │ │ ├── cat.rs
|
||||
│ │ │ ├── cp.rs
|
||||
│ │ │ └── tail.rs
|
||||
│ │ │ └── touch.rs
|
||||
│ │ │ └── wget.rs
|
||||
│ │ ├── system_ops/ # 系统操作相关命令
|
||||
│ │ │ └── top.rs
|
||||
│ │ └── mod.rs # 命令模块定义
|
||||
│ ├── main.rs # 主程序入口
|
||||
├── Cargo.toml # Cargo 配置文件
|
||||
└── README.md # 项目说明文档
|
||||
```
|
||||
|
||||
## 安装与构建
|
||||
|
||||
### 前置条件
|
||||
|
||||
- 需要安装 [Rust 编译工具链](https://www.rust-lang.org/)
|
||||
|
||||
### 构建步骤
|
||||
|
||||
1. 克隆项目到本地:
|
||||
|
||||
```bash
|
||||
git clone https://gitee.com/zhub_dev/WinShell.git
|
||||
cd WinShell
|
||||
```
|
||||
|
||||
2. 构建项目:
|
||||
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
3. 运行项目:
|
||||
|
||||
```bash
|
||||
cargo run -- <command> [args...]
|
||||
```
|
||||
|
||||
例如,列出当前目录的文件:
|
||||
|
||||
```bash
|
||||
cargo run -- ls
|
||||
```
|
||||
|
||||
## 使用说明
|
||||
|
||||
WinShell 提供以下命令,支持常见的文件和系统操作:
|
||||
|
||||
### 文件操作命令
|
||||
|
||||
- `cp`:复制文件或目录
|
||||
- `ls`:列出文件和目录
|
||||
- `mv`:移动或重命名文件/目录
|
||||
- `mkdir`:创建目录
|
||||
- `rm`:删除文件或目录
|
||||
- `cat`:显示文件内容
|
||||
- `tail`:查看文件末尾内容
|
||||
- `touch`:创建一个空文件
|
||||
- `wget`:下载文件
|
||||
|
||||
### 系统操作命令
|
||||
|
||||
- `top`:显示系统的进程列表
|
||||
- `kill`:终止一个进程
|
||||
|
||||
### 示例(命令调试模式)
|
||||
|
||||
- 列出当前目录的文件(`ls` 命令):
|
||||
|
||||
```bash
|
||||
cargo run -- ls
|
||||
```
|
||||
|
||||
- 删除文件(`rm` 命令):
|
||||
|
||||
```bash
|
||||
cargo run -- rm <文件名>
|
||||
```
|
||||
|
||||
- 显示文件内容(`cat` 命令):
|
||||
|
||||
```bash
|
||||
cargo run -- cat <文件名>
|
||||
```
|
||||
|
||||
- 复制文件(`cp` 命令):
|
||||
|
||||
```bash
|
||||
cargo run -- cp <源文件> <目标文件>
|
||||
```
|
||||
### 安装 WinShell 命令到 windows
|
||||
`(待补充)`
|
||||
|
||||
## 参数说明
|
||||
|
||||
每个命令支持的参数有所不同,以下是一些常用的选项:
|
||||
|
||||
- `ls -l`:以详细模式列出文件
|
||||
- `tail -n <行数>`:显示文件的最后几行
|
||||
- `top -n <显示进程数>`:显示指定数量的进程
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 某些命令可能需要管理员权限才能执行。
|
||||
2. 目前只支持在 Windows 系统上运行。
|
||||
|
||||
## 贡献
|
||||
|
||||
欢迎对 WinShell 项目进行贡献,提交 Pull Request 或 Issue。
|
78
src/commands/file_ops/cp.rs
Normal file
78
src/commands/file_ops/cp.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
/// 执行 cp 命令
|
||||
pub fn execute(args: &[String]) {
|
||||
// 检查参数数量
|
||||
if args.len() != 2 {
|
||||
eprintln!("用法: cp <源文件/目录> <目标文件/目录>");
|
||||
return;
|
||||
}
|
||||
|
||||
let source = &args[0];
|
||||
let target = &args[1];
|
||||
|
||||
// 检查源路径是否存在
|
||||
let source_path = Path::new(source);
|
||||
if !source_path.exists() {
|
||||
eprintln!("错误: 源 '{}' 不存在", source);
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断源是文件还是目录
|
||||
if source_path.is_dir() {
|
||||
copy_directory(source_path, target);
|
||||
} else {
|
||||
copy_file(source_path, target);
|
||||
}
|
||||
}
|
||||
|
||||
/// 复制文件
|
||||
fn copy_file(source: &Path, target: &str) {
|
||||
let target_path = Path::new(target);
|
||||
|
||||
// 检查目标是否已存在
|
||||
if target_path.exists() {
|
||||
eprintln!("错误: 目标 '{}' 已存在", target);
|
||||
return;
|
||||
}
|
||||
|
||||
// 复制文件
|
||||
match fs::copy(source, target_path) {
|
||||
Ok(_) => println!("文件 '{}' 成功复制到 '{}'", source.display(), target),
|
||||
Err(e) => eprintln!("复制文件时出错: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
/// 递归复制目录
|
||||
fn copy_directory(source: &Path, target: &str) {
|
||||
let target_path = Path::new(target).join(source.file_name().unwrap()); // 目标目录下的文件名
|
||||
|
||||
// 创建目标目录
|
||||
if let Err(e) = fs::create_dir_all(&target_path) {
|
||||
eprintln!("创建目标目录时出错: {}", e);
|
||||
return;
|
||||
}
|
||||
|
||||
// 遍历源目录中的所有文件和子目录
|
||||
if let Ok(entries) = fs::read_dir(source) {
|
||||
for entry in entries {
|
||||
match entry {
|
||||
Ok(entry) => {
|
||||
let entry_path = entry.path();
|
||||
let target_entry_path = target_path.join(entry.file_name());
|
||||
|
||||
// 如果是目录,递归复制
|
||||
if entry_path.is_dir() {
|
||||
copy_directory(&entry_path, target_entry_path.to_str().unwrap());
|
||||
} else {
|
||||
copy_file(&entry_path, target_entry_path.to_str().unwrap());
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!("读取目录时出错: {}", e),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eprintln!("读取源目录时出错: {}", source.display());
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
// 引入 colored 库以支持颜色输出
|
||||
use chrono::NaiveDateTime;
|
||||
use chrono::DateTime;
|
||||
use colored::*;
|
||||
use std::fs::{self, DirEntry, Metadata};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
@@ -183,13 +183,13 @@ fn print_file_color(entry: &DirEntry, file_name: &str) {
|
||||
}
|
||||
|
||||
// 将文件名称做颜色格式化
|
||||
fn format_file_name(file_name: &str) -> String {
|
||||
/*fn format_file_name(file_name: &str) -> String {
|
||||
if file_name.starts_with('.') {
|
||||
file_name.yellow().to_string() // 隐藏文件用黄色显示
|
||||
} else {
|
||||
file_name.to_string()
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// 将系统时间格式化为可读的字符串
|
||||
fn format_system_time(system_time: SystemTime) -> String {
|
||||
@@ -198,6 +198,6 @@ fn format_system_time(system_time: SystemTime) -> String {
|
||||
.unwrap_or_default()
|
||||
.as_secs();
|
||||
// 使用 NaiveDateTime::from_timestamp 将时间戳转换为日期时间
|
||||
let naive_datetime = NaiveDateTime::from_timestamp(datetime as i64, 0);
|
||||
let naive_datetime = DateTime::from_timestamp(datetime as i64, 0).unwrap().time();
|
||||
format!("{}", naive_datetime.format("%Y-%m-%d %H:%M:%S"))
|
||||
}
|
||||
|
@@ -2,3 +2,7 @@ pub mod ls;
|
||||
pub mod mv;
|
||||
pub mod rm;
|
||||
pub mod touch;
|
||||
pub mod tail;
|
||||
pub mod cp;
|
||||
pub mod pwd;
|
||||
pub mod wget;
|
||||
|
@@ -12,7 +12,7 @@ pub fn execute(args: &[String]) {
|
||||
let mut interactive = false; // 是否启用交互模式
|
||||
let mut force = false; // 是否启用强制模式
|
||||
let mut sources = vec![]; // 源文件或目录列表
|
||||
let mut target = String::new(); // 目标路径
|
||||
let target; // 目标路径
|
||||
|
||||
// 解析命令行参数
|
||||
for arg in &args[..args.len() - 1] {
|
||||
|
15
src/commands/file_ops/pwd.rs
Normal file
15
src/commands/file_ops/pwd.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use std::env;
|
||||
|
||||
pub fn execute() {
|
||||
// 获取当前工作目录
|
||||
match env::current_dir() {
|
||||
Ok(path) => {
|
||||
// 输出工作目录路径
|
||||
println!("{}", path.display());
|
||||
}
|
||||
Err(e) => {
|
||||
// 如果获取失败,输出错误信息
|
||||
eprintln!("错误: 无法获取当前工作目录 - {}", e);
|
||||
}
|
||||
}
|
||||
}
|
127
src/commands/file_ops/tail.rs
Normal file
127
src/commands/file_ops/tail.rs
Normal file
@@ -0,0 +1,127 @@
|
||||
use regex::Regex;
|
||||
use std::fs;
|
||||
use std::io::{self, BufReader, Read, Seek};
|
||||
use std::path::Path;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
/// 执行 tail 命令
|
||||
pub fn execute(args: &[String]) {
|
||||
if args.is_empty() {
|
||||
eprintln!("用法: tail [-n <行数>] [-f] <文件名>");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut line_count: usize = 10; // 默认行数
|
||||
let mut follow: bool = false; // 默认不跟踪
|
||||
let mut file_path: Option<&String> = None;
|
||||
|
||||
// 解析命令行参数
|
||||
let mut iter = args.iter();
|
||||
while let Some(arg) = iter.next() {
|
||||
match arg.as_str() {
|
||||
"-f" => {
|
||||
follow = true;
|
||||
}
|
||||
"-n" => {
|
||||
if let Some(next) = iter.next() {
|
||||
line_count = match next.parse::<usize>() {
|
||||
Ok(n) => n,
|
||||
Err(_) => {
|
||||
eprintln!("错误: 行数必须是一个非负整数");
|
||||
return;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
eprintln!("错误: '-n' 选项后需要指定行数");
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// -{n}f 的处理, n代表数字, 使用正则匹配
|
||||
let re = Regex::new(r"-(\d+)(f)?").unwrap();
|
||||
if let Some(cap) = re.captures(arg) {
|
||||
let num_str = cap.get(1).unwrap().as_str();
|
||||
line_count = match num_str.parse::<usize>() {
|
||||
Ok(n) => n,
|
||||
Err(_) => {
|
||||
eprintln!("错误: 行数必须是一个非负整数");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// 检查是否有 -f 选项
|
||||
if cap.get(2).is_some() {
|
||||
follow = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 假定第一个非选项参数是文件路径
|
||||
file_path = Some(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查文件路径是否提供
|
||||
let file_path = match file_path {
|
||||
Some(path) => Path::new(path),
|
||||
None => {
|
||||
eprintln!("错误: 需要指定文件名");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// 检查文件是否存在
|
||||
if !file_path.exists() {
|
||||
eprintln!("错误: 文件 '{}' 不存在", file_path.display());
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取文件内容并输出最后 n 行
|
||||
if let Err(e) = tail_file(file_path, line_count, follow) {
|
||||
eprintln!("读取文件时出错: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// 读取文件并输出最后 n 行或持续跟踪
|
||||
fn tail_file(file_path: &Path, line_count: usize, follow: bool) -> io::Result<()> {
|
||||
let file = fs::OpenOptions::new().read(true).open(file_path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
// 读取文件内容
|
||||
let mut contents = String::new();
|
||||
reader.read_to_string(&mut contents)?;
|
||||
|
||||
// 输出最后 n 行
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
let total_lines = lines.len();
|
||||
let start_index = total_lines.saturating_sub(line_count);
|
||||
|
||||
for line in &lines[start_index..] {
|
||||
println!("{}", line);
|
||||
}
|
||||
|
||||
// 如果跟踪,持续监视文件变化
|
||||
if follow {
|
||||
let mut last_size = contents.len();
|
||||
loop {
|
||||
thread::sleep(Duration::from_secs(1)); // 每隔一秒检查一次
|
||||
let current_size = fs::metadata(file_path)?.len() as usize;
|
||||
if current_size > last_size {
|
||||
// 读取新内容
|
||||
let mut new_contents = String::new();
|
||||
let mut file = fs::OpenOptions::new().read(true).open(file_path)?;
|
||||
file.seek(io::SeekFrom::Start(last_size as u64))?;
|
||||
file.read_to_string(&mut new_contents)?;
|
||||
|
||||
// 输出新内容
|
||||
for line in new_contents.lines() {
|
||||
println!("{}", line);
|
||||
}
|
||||
last_size = current_size; // 更新文件大小
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
49
src/commands/file_ops/wget.rs
Normal file
49
src/commands/file_ops/wget.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use std::fs::File;
|
||||
use std::io::{self, copy};
|
||||
use std::path::Path;
|
||||
use reqwest::blocking::get;
|
||||
use reqwest::Url;
|
||||
|
||||
pub fn execute(args: &[String]) {
|
||||
if args.len() != 1 {
|
||||
eprintln!("用法: wget <URL>");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut url = args[0].clone();
|
||||
|
||||
// 如果不含 https 和 http 补全
|
||||
if !url.starts_with("https://") && !url.starts_with("http://") {
|
||||
url = format!("https://{}", url);
|
||||
// url = &(new_url.clone());
|
||||
println!("URL 不包含协议,已自动补全为: {}", url);
|
||||
}
|
||||
|
||||
let url = &url;
|
||||
|
||||
// 检查 URL 是否有效
|
||||
if let Err(_) = Url::parse(url) {
|
||||
eprintln!("错误: 无效的 URL");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取文件名
|
||||
let file_name = url.split('/').last().unwrap_or("downloaded_file");
|
||||
|
||||
// 下载文件
|
||||
match download_file(url, file_name) {
|
||||
Ok(_) => println!("文件已成功下载: {}", file_name),
|
||||
Err(e) => eprintln!("下载失败: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
// 下载文件的函数
|
||||
fn download_file(url: &str, file_name: &str) -> Result<(), io::Error> {
|
||||
let response = get(url).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||
let mut dest = File::create(Path::new(file_name))?;
|
||||
let mut content = response;
|
||||
|
||||
// 将下载的内容写入文件
|
||||
copy(&mut content, &mut dest)?;
|
||||
Ok(())
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
|
||||
pub mod file_ops;
|
||||
pub mod directory_ops;
|
||||
pub mod text_ops;
|
||||
pub mod text_ops;
|
||||
pub mod system_ops;
|
37
src/commands/system_ops/kill.rs
Normal file
37
src/commands/system_ops/kill.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
// src/commands/system_ops/kill.rs
|
||||
use std::process::Command;
|
||||
|
||||
pub fn execute(args: &[String]) {
|
||||
// 检查参数数量
|
||||
if args.len() < 1 {
|
||||
eprintln!("用法: kill <PID>");
|
||||
return;
|
||||
}
|
||||
|
||||
let pid: u32 = match args[0].parse() {
|
||||
Ok(pid) => pid,
|
||||
Err(_) => {
|
||||
eprintln!("错误: 无效的 PID '{}'", args[0]);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// 使用 taskkill 命令终止进程
|
||||
let output = Command::new("taskkill")
|
||||
.arg("/PID")
|
||||
.arg(pid.to_string())
|
||||
.arg("/F") // 强制终止进程
|
||||
.output();
|
||||
|
||||
match output {
|
||||
Ok(output) => {
|
||||
if output.status.success() {
|
||||
println!("成功: 终止进程 {}", pid);
|
||||
} else {
|
||||
let err = String::from_utf8_lossy(&output.stderr);
|
||||
eprintln!("错误: 无法终止进程 {}: {}", pid, err);
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!("错误: 执行 taskkill 失败: {}", e),
|
||||
}
|
||||
}
|
3
src/commands/system_ops/mod.rs
Normal file
3
src/commands/system_ops/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
pub mod top;
|
||||
pub mod kill;
|
85
src/commands/system_ops/top.rs
Normal file
85
src/commands/system_ops/top.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use std::{thread, time};
|
||||
use colored::Colorize;
|
||||
// src/commands/system_ops/top.rs
|
||||
use sysinfo::{Process, System};
|
||||
|
||||
pub fn execute(args: &[String]) {
|
||||
let mut system = System::new_all();
|
||||
let mut refresh_interval = time::Duration::from_secs(3); // 默认刷新间隔
|
||||
let mut display_count = usize::MAX; // 默认显示所有进程
|
||||
let mut specific_pid: Option<u32> = None;
|
||||
|
||||
// 解析命令行参数
|
||||
let mut i = 1;
|
||||
while i < args.len() {
|
||||
match args[i].as_str() {
|
||||
"-n" => {
|
||||
i += 1;
|
||||
if i < args.len() {
|
||||
display_count = args[i].parse().unwrap_or(usize::MAX);
|
||||
}
|
||||
}
|
||||
"-s" => {
|
||||
i += 1;
|
||||
if i < args.len() {
|
||||
if let Ok(seconds) = args[i].parse::<u64>() {
|
||||
refresh_interval = time::Duration::from_secs(seconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
"-p" => {
|
||||
i += 1;
|
||||
if i < args.len() {
|
||||
specific_pid = args[i].parse().ok();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// 主循环
|
||||
loop {
|
||||
// 更新系统信息
|
||||
system.refresh_all();
|
||||
|
||||
// 获取当前所有进程的信息
|
||||
let mut processes: Vec<&Process> = system.processes().iter().map(|(_, p)| p).collect();
|
||||
|
||||
// 过滤特定 PID
|
||||
if let Some(pid) = specific_pid {
|
||||
//processes.retain(|&p| p.pid() == pid);
|
||||
processes.retain(|&p| p.pid().as_u32() == pid);
|
||||
}
|
||||
|
||||
// 按照 CPU 使用率进行排序
|
||||
processes.sort_by(|a, b| b.cpu_usage().partial_cmp(&a.cpu_usage()).unwrap_or(std::cmp::Ordering::Equal));
|
||||
|
||||
// 打印表头
|
||||
println!("{:<5}\t{:<25}\t{:<8}\t{:<10}\t{:<10}",
|
||||
"PID", "Name", "CPU(%)", "Mem(KB)", "State");
|
||||
println!("{}", "-".repeat(80));
|
||||
|
||||
// 取 processes 前10条记录
|
||||
processes.truncate(15);
|
||||
|
||||
// 打印进程信息
|
||||
for process in processes.iter().take(display_count) {
|
||||
let pid = process.pid();
|
||||
let name = process.name().to_str().unwrap_or("N/A");
|
||||
let cpu_usage = process.cpu_usage();
|
||||
let memory = process.memory();
|
||||
let status = if process.status().eq(&sysinfo::ProcessStatus::Run) {
|
||||
"运行中"
|
||||
} else {
|
||||
"已停止"
|
||||
};
|
||||
|
||||
println!("{:<5}\t{:<25}\t{:<8}\t{:<10}\t{:<10}",
|
||||
pid, name.blue(), cpu_usage, (memory / 1024) as u32, status);
|
||||
}
|
||||
|
||||
// 等待一段时间后刷新
|
||||
thread::sleep(refresh_interval);
|
||||
}
|
||||
}
|
@@ -14,12 +14,18 @@ fn main() {
|
||||
let command_args = &args[2..];
|
||||
|
||||
match command.as_str() {
|
||||
"cp" => commands::file_ops::cp::execute(command_args),
|
||||
"ls" => commands::file_ops::ls::execute(command_args),
|
||||
"mv" => commands::file_ops::mv::execute(command_args),
|
||||
"pwd" => commands::file_ops::pwd::execute(),
|
||||
"rm" => commands::file_ops::rm::execute(command_args),
|
||||
"tail" => commands::file_ops::tail::execute(command_args),
|
||||
"touch" => commands::file_ops::touch::execute(command_args),
|
||||
"wget" => commands::file_ops::wget::execute(command_args),
|
||||
"mkdir" => commands::directory_ops::mkdir::execute(command_args),
|
||||
"cat" => commands::text_ops::cat::execute(command_args),
|
||||
"top" => commands::system_ops::top::execute(command_args),
|
||||
"kill" => commands::system_ops::kill::execute(command_args),
|
||||
_ => eprintln!("未知命令: {}", command),
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user