cat 命令原理及源代码分析

本文详细分析了Linux系统中cat命令的工作原理和源代码,讲解了其基本功能,包括读取文件、格式化输出等,并探讨了处理IO中断、内存管理等复杂问题。cat命令在实现中通过安全的读写操作处理信号中断,通过状态变量管理空行处理。文章还介绍了如何处理字符映射、行号显示和空行特殊处理,展示了如何在多个文件间传递状态信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

在 linux 上最常用的命令之一莫过于 cat 命令,用它来快速查看文件内容再合适不过了。
cat 命令也是 coreutils 包中的一个工具,coreutils 提供了一系列工具来操作文件,cat 是其中最基本的工具,相关的还有 tac, head, tail, nl, less, more。

如果想学习文件操作的相关知识,通过这几个工具的深入学习,完全可以学到想要的知识点。接下来会有一系列的文章来逐个分析上述工具,本文作为本系列的一个开篇,讲述 cat 的原理和源代码中的一些亮点。

本文源代码使用 cat (GNU coreutils) 8.21 版本。

原理

cat 命令的基本功能并不复杂,常用的场景是用 cat 将一个文件的内容输出到屏幕上,比如:cat /etc/hosts会在屏幕上得到该文件的内容。
基本原理是从标准输入读入要 cat 的文件列表,然后逐个打开,读入文件内容,再将内容输出到标准输出上。整个功能并不复杂,甚至C语言的初学者都可以实现出一个可用的版本。

基本功能

命令 cat --help会得到它具体的命令行参数格式,通过不同的参数组合影响 cat 输出的格式,也可以说所有的命令行参数都是针对输出格式的,可能只有20%的情况下会使用这些参数,但针对这些参数的实现缺占据了几乎 80% 的代码量,二八定律在这里有惊人的准确。

这些参数里,常用的或者会影响到实现复杂度的参数有:

  • -E 在输出的每行行尾显示$
  • -n 在输出的每行开头显示行号
  • -b 只对非空白行计算行号
  • -s 忽略连续的空行
  • -v 显示不可打印的字符
    这里比较复杂的是 -s 参数,因为它涉及到上下文的状态。后面可以看到针对这个参数有大量的代码实现。-v 参数的复杂度略低,它需要实现一个针对非打印字符到可打印字符的关系映射,但这个映射并没有上下文状态,所以还比较简单。

另外为了正确性和运行效率,程序还做了一些考虑,后面逐一会提到。

基本功能实现

如果只是一个最简单的 cat 程序,不考虑任何对输出格式的影响,那么程序实现出来应该是这样的:

  1. 打开输入文件 infile.
  2. 从 infile 里读一段数据存在 buffer 里.
  3. 将 buffer 里的数据写到 STDOUT_FILENO 里
  4. 重复上述过程直到 infile 的结尾
    整个执行模式符合 unix 程序的功能单一的精神,从文件或者 STDIN_FILENO读入数据,向 STDOUT_FILENO 输出数据。

避免输入输出都指向同一个文件

STDIN_FILENO 和 STOUT_FILENO 都是 unix 平台的数据接口,他们通过重定向可以是任何文件。
因此在 cat 程序开头也会查看检查输入和输出文件的 inode 标号,看是否是同一个文件。cat 不允许输入和输出是同一个文件。但是对 STDIN_FILENO 留了例外,所以 cat >&1竟然是合法的,我并没有想明白这样做的原因。

模拟实现

根据上面的思想,我们模拟实现一段核心代码:

// 课堂教学用的代码,不能用在生产环境。
int too_simple_cat(int infd)
{
    char buf[1024 * 128];
    size_t buf_size = sizeof(buf);
    int n_read = 0;
    do {
        n_read = read(infd, buf, buf_size);
        if (n_read == 0)
            return 0;
        else if (n_read == -1) {
            perror("too_simple_cat() read error");
            return -1;
        }
        else {
            if (write(STDOUT_FILENO, buf, n_read) < 0) {
                perror
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值