Rust 开发命令行工具(上)(一)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Rust 开发命令行工具(上)(一)

你必须按所想去生活,否则只能按生活去想。 --王小波

大家好,我是柒八九

作为一个前端/Rust/AI知识博主,之前的文章中,大部分篇幅都是关于前端的知识分享,而对RustAI的内容只是做了几篇内容梳理和介绍。

而,我们今后的重心也会逐渐偏移,势必能达到前端/Rust/AI三足鼎立的局面。


这里也和很多精神股东做一次简短的汇报,之前答应大家多出一些Rust相关的文章,由于工作和个人事务侵占大部分学习和总结的时间,所以迟迟没有兑现承诺。也很感谢大部分老粉能不离不弃,在这里先叩谢大家了。


你们的支持也是我输入内容的精神支柱,同时也很感谢有些远在天涯海角的朋友,不停的给出建议和改进意见,Last but not least,由于有些技术能力的有限,在一些表达方式和技术深度方向上,有很多瑕疵。也希望以后大家,互相学习,共同进步。

好了,估计大家不想听我在这里一个人聒噪了,那么就进入我们今天的主题。


前言

在上一篇致所有渴望学习Rust的人的信中我们介绍了Rust可以在命令行工具上也大有建树。

image.png

现在就是我们兑现承诺的时候了。

Rust是一种静态编译的、快速的语言,具有出色的工具支持和迅速增长的生态系统。这使它非常适合编写命令行应用程序。

通过编写具有简单CLI的程序,对于那些初学者来说是一个很好的练习,也是我们需要循序渐进的一个过程。毕竟,大家刚开始接触一个新的语言都是从Hello World的入手的,但是这种Demo级别的程序,可以说是闭门造车,没有任何的实际价值。并且这种程序是难登大雅之堂的。

所以,我们今天来通过一个简单的CLI来巩固之前的内容,并且写出的东西也可以在公司应用场景中有用武之地。

所以说选择很重要,我们不要成为别人口中说的你之所以穷,是因为你不够努力的人。


我们在讲解代码中,有一些基础语法会一带而过,也就是说,已经默认大家已经有Rust基础了。如果,你是一个Rust初学者,我们也提供了Rust学习笔记系列,可以快速掌握基础语法。当然,里面的有一些内容也会做一些简单的梳理和讲解。这个就因人而异了,看大家实际情况吧。


由于篇幅的原因,我们打算写三篇文章(上/中/下),来介绍如何用Rust来编写属于自己的命令行工具。 今天是第一篇文章,我们主要的目的是用Rust写出一个可用的命令行工具。属于本地应用级别,现在先不要嗤之以鼻,我们后面的2篇文章,会逐步优化这个项目,然后达到最后发版供别人使用的级别。


你能所学到的知识点

  1. 前置知识点
  2. 项目设置
  3. 解析命令行参数
  4. 解析文件内容
  5. 更人性化的错误报告
  6. 信息输出处理
  7. 代码展示 (这个狠重要) 👈 徐志胜语音包

好了,天不早了,干点正事哇。



1. 前置知识点

前置知识点,只是做一个概念的介绍,不会做深度解释。因为,这些概念在下面文章中会有出现,为了让行文更加的顺畅,所以将本该在文内的概念解释放到前面来。如果大家对这些概念熟悉,可以直接忽略


同时,由于阅读我文章的群体有很多,所以有些知识点可能我视之若珍宝,尔视只如草芥,弃之如敝履。以下知识点,请酌情使用

grep 简介

grep 是一个常用的命令行工具,用于在文本文件中搜索指定的文本模式返回匹配的行。其名称来源于 global regular expression print(全局正则表达式打印),它最初是在UNIX操作系统中开发的,现在已经成为大多数Unix-like系统(包括Linux)的标准工具之一。grep 的主要功能是查找文件中包含特定文本的行,并将这些行打印到标准输出(通常是终端)上。

以下是 grep 命令的基本语法:

grep [选项] 模式 [文件...]
  • 选项:可以是一些控制搜索行为的可选标志,例如 -i(忽略大小写)、-r(递归搜索目录)、-l(仅显示包含匹配项的文件名)等。
  • 模式:要搜索的文本模式,通常使用正则表达式来指定。
  • 文件:要搜索的文件列表。如果不指定文件,则 grep 将从标准输入中读取数据。

一些常见的 grep 用法示例:

  1. 在文件中搜索特定字符串(不区分大小写):
grep -i "search_text" file.txt
  1. 在多个文件中递归搜索特定字符串并显示包含匹配项的文件名:
grep "pattern.*text" file.txt
  1. 使用正则表达式搜索匹配模式:
grep -c "pattern" file.txt
  1. 统计匹配的行数:
grep -c "pattern" file.txt

grep 是一个强大的文本搜索工具,可以在各种情况下用于过滤、查找和处理文本数据。它的灵活性和正则表达式支持使得它在命令行中非常有用。


让我们编写一个小型的类似grep的工具。给它起一个霸气侧漏的名称,那就叫它 - f789吧。


我们可以在我们本地,创建一个文件夹,作为项目的工作目录。(这就看个人喜好,自行决断了)

最终,我们希望能够像这样运行我们的工具:

// 创建一个text.txt文件,并向其写入指定内容
echo "front:789" > text.txt
echo "province:山西" >> text.txt
echo "rust: hello" >> text.txt
$ f789 rust test.txt
rust: hello
$ f789 --help
// 提供一些帮助选项

本文中rustc采用的是1.72.0 (5680fa18f 2023-08-23)的版本。并且在Cargo.toml文件的[package]部分中设置edition = "2021"

如果,版本不对会有一些库的兼容性问题,所以最好大家在运行代码前,做一下代码配置和相关的处理。具体的配置和升级可以参考Rust环境配置和入门指南或者官网.

在使用对应命令升级之前,这里有一个小的提示,如果你在Mac中使用brew安装过Rust,你最好检测一下对应的版本信息。可以使用rustc --version命令,会返回指定版本信息。例如:rustc 1.68.2 (9eb3afe9e 2023-03-27) (built from a source tarball)


但是,(built from a source tarball)这一部分表示 Rust 编译器不是通过二进制发布版安装的,而是从 Rust 源代码中编译生成的。这通常是因为我们手动构建 Rust 或从源代码仓库中获取 Rust 的最新版本。这种情况的话,在使用rustup update进行版本更新的时候,会有问题。所以我推荐安装官方的二进制发布版。(也就是官网的处理方式)


2. 项目设置

如果你尚未安装Rust,可以参考我们之前的文章Rust环境配置和入门指南。然后,打开一个终端并导航到我们想要放置应用程序代码的目录。

首先,在存储编程项目的目录中运行以下命令:cargo new f789。如果我们查看新创建的f789目录,我们将会找到一个典型的Rust项目设置:

image.png

我们用erdtree进行页面结构展示。当然,我们也可以用tree命令。一切的理所应当都是命运的暗中撮合。因为erdtree也是Rust写的。

  • 一个Cargo.toml文件,其中包含我们项目的元数据,包括我们使用的依赖/外部库列表。
  • 一个src/main.rs文件,它是我们二进制文件的入口点

如果我们可以在f789目录中执行cargo run并获得一个Hello World,那么我们已经设置好了。

项目运行

$ cargo new f789
     Created binary (application) `f789` package
$ cd f789/
$ cargo run
   Compiling f789 v0.1.0 (项目存储路径)
    Finished dev [unoptimized + debuginfo] target(s) in 0.70s
     Running `target/debug/f789`
Hello, world!

image.png


3. 解析命令行参数

一般的CLI都支持参数的输入:例如tree -a -L 2或者我们之前的erd -i -I -L 2 -y inverted

我们也想让我们的CLI具有这个功能:

$ f789 front test.txt

我们期望我们的程序查看test.txt并打印出包含front的行。但是我们如何获取这两个值呢?

程序名称后面的文本通常被称为命令行参数命令行标志(特别是当它们看起来像--这样时)。

在操作系统内部通常将它们表示为字符串列表 - 简而言之,它们由空格分隔。

有许多方法可以探查和识别这些参数,以及如何将它们解析成更容易处理的形式。我们还需要告诉使用我们程序的用户需要提供哪些参数以及它们期望的格式是什么。


获得参数

标准库中包含了函数std::env::args(),它提供了给定参数的迭代器。第一项(索引为0)是我们程序被调用的名称(例如,f789),其后的项是用户在后面写的内容。

通过这种方式获取原始参数非常容易(在文件src/main.rs中,在fn main() {之后):

let pattern = std::env::args().nth(1).expect("未提供模式");
let path = std::env::args().nth(2).expect("未提供路径");

这里,pattern将包含用户输入的第一个参数,path将包含用户输入的第二个参数。如果用户没有提供这些参数,程序将会报错并显示相应的错误消息。


将 CLI 参数自定义数据类型

与将CLI参数视为一堆文本相比,将其视为表示程序输入的自定义数据类型通常更有帮助。

看看 f789 front test.txt:有两个参数,首先是模式(要查找的字符串),然后是路径(要查找的文件)。

此外还有其它需要注意的点?首先,它们都是必需的。我们还没有讨论默认值,因此我们期望用户始终提供两个值。此外,我们还可以谈谈它们的类型:模式应该是一个字符串,而第二个参数应该是文件的路径

Rust中,通常以处理的数据为中心来构建程序,因此以这种方式看待CLI参数非常合适。让我们做一层数据抽象(在文件src/main.rs中,在fn main() {之前):

struct Cli {
    pattern: String,
    path: std::path::PathBuf,
}

这定义了一个新的结构体(struct),它有两个字段来存储数据:patternpath

注意:PathBuf类似于String,但用于跨平台的文件系统路径。

现在,我们需要将我们的程序接收到的实际参数转换为这种形式。一种选项是手动解析操作系统获取的字符串列表并自己构建结构。代码可能如下所示:

let pattern = std::env::args().nth(1).expect("未提供模式");
let path = std::env::args().nth(2).expect("未提供路径");
let args = Cli {
    pattern: pattern,
    path: std::path::PathBuf::from(path),
};

这种方法是可行的,但不够方便。上面的方式无法满足,用户天马行空的创造力。例如:遇到类似--pattern="front"--pattern "front"--help 的参数形式上面的代码就捉襟见肘了。

也就是说,上面的代码不够优雅。

相关文章
|
2月前
|
Rust 资源调度 安全
为什么使用 Rust over C++ 进行 IoT 解决方案开发
为什么使用 Rust over C++ 进行 IoT 解决方案开发
73 7
|
4月前
|
Rust 安全 JavaScript
探索Rust在系统编程领域的前景:虚拟机和编译器开发的新篇章
【8月更文挑战第31天】在系统编程领域,性能与安全性至关重要。Rust作为一种新兴语言,凭借其独特的内存安全和并发特性,正逐渐成为虚拟机和编译器开发的首选。本文通过案例分析,探讨Rust在这些领域的应用,例如Facebook的Compiler VM (CVM)项目和实验性的JavaScript JIT编译器Mithril。Rust的静态类型系统和所有权模型确保了高性能和安全性,而其强大的包管理和库生态则简化了虚拟机的开发。随着Rust社区的不断成熟,预计未来将有更多基于Rust的创新项目涌现,推动系统编程的发展。对于追求高性能和安全性的开发者而言,掌握Rust将成为一个重要战略方向。
81 1
|
5月前
|
Rust 程序员 开发者
使用 Rust 开发一款类似于 GitBook 的程序
**Rust新手开发者分享开源项目 Typikon**:模仿MDBook,致力于简单Markdown到在线书的渲染。[GitHub](https://github.com/auula/typikon)上可找到源码,欢迎初学者一同学习与贡献。体验轻松构建静态网站,探索Rust之旅。🌟 加入讨论,共建更易用的GitBook替代品。在线文档见[https://typikonbook.github.io](https://typikonbook.github.io)。
40 1
|
6月前
|
Rust Unix Windows
使用Cargo国内镜像提升Rust开发效率
使用Cargo国内镜像提升Rust开发效率
521 0
|
7月前
|
Rust 安全 程序员
拜登:“一切非 Rust 项目均为非法”,开发界要大变天?
白宫国家网络总监办公室(ONCD,以下简称网总办)在本周一发布的报告中说道:“程序员编写代码并非没有后果,他们的⼯作⽅式于国家利益而言至关重要。”
134 1
|
7月前
|
Rust 前端开发 JavaScript
Rust在前端与全栈开发中的实践探索
随着Rust语言的日渐成熟,其应用场景已经从后端扩展到前端和全栈开发领域。本文将深入探讨Rust语言在前端与全栈开发中的实际应用案例,分析Rust语言在这些领域的优势和面临的挑战,并展望Rust未来的发展趋势。
|
存储 Rust 测试技术
Rust 开发命令行工具(中)(三)
Rust 开发命令行工具(中)(三)
150 0
|
Rust 测试技术 人机交互
Rust 开发命令行工具(中)(二)
Rust 开发命令行工具(中)(二)
|
存储 Rust JavaScript
Rust 开发命令行工具(中)(一)
Rust 开发命令行工具(中)(一)
|
存储 关系型数据库 Shell
使用 Rust 开发 PostgreSQL 存储过程
pgxr 使用 Rust 来编写 PostgreSQL 的扩展函数(相当于存储过程)。 项目地址:https://github.com/clia/pgxr 使用这个星球上最快的、高效、安全、有趣的编程语言,来为世界上功能最强大的开源关系数据库编写库内的程序! 试想,当你从数据库中查询出 1000 条记录用于程序处理时,当你的程序是数据库内的程序时,你根本无需将这 1000 条结果通过 PostgreSQL 的通讯协议走网络传输到应用程序里,在应用程序里分配这么大一块内存来装这些数据,再来进行处理。
7332 0