You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何自定义tee.c程序与系统tee命令输出存在差异?

问题原因分析与排查方案

核心原因推测

你遇到的问题大概率是代码对命令行参数的处理逻辑错误,再加上文件写入流程存在疏漏,具体表现为:

  • 错误地将命令行传入的文件名(test.txt)当作输出内容打印到终端,而非将其作为目标文件路径去打开写入。
  • 没有正确读取标准输入(stdin)的内容,自然也就无法将ls -l的输出写入文件,导致文件大小为0。

常见错误点拆解

1. 命令行参数解析错误

系统tee的逻辑是:跳过程序名(argv[0]),将后续第一个参数作为输出文件路径,然后从stdin读取数据并同时输出到终端和文件。
如果你的实现代码没有做参数判断(比如没检查argc >= 2),或者错误地遍历输出了argv数组的所有内容,就会把test.txt打印到终端,同时根本没去打开这个文件写入数据。

2. 文件打开与写入逻辑错误

  • 打开模式错误:比如用了O_RDONLY(只读)模式打开文件,后续写入操作会直接失败;或者没有添加O_CREAT和O_TRUNC参数,导致文件无法创建或清空原有内容。
  • 写入流程缺失:代码可能只实现了向终端(stdout)输出,完全没处理文件写入;或者读取stdin的逻辑有问题(比如只读取一次就退出,没循环到EOF)。

3. 错误处理缺失

很多实现会忽略系统调用的返回值检查,比如open返回-1(文件打开失败)、read/write返回值不等于预期字节数时,没有报错就继续执行,导致问题被隐藏。

排查与修复步骤

  1. 检查参数解析代码
    确认代码中是否正确提取了目标文件名:

    • 必须判断argc >= 2,否则提示用法错误(比如Usage: ./tee filename)。
    • 用argv[1]作为文件路径,而非遍历输出所有argv元素。
  2. 验证文件打开逻辑
    如果用系统调用,确保打开文件的参数正确:

    int fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
    
    • O_WRONLY:以只写模式打开
    • O_CREAT:文件不存在则创建
    • O_TRUNC:文件存在则清空内容
    • 0644:设置文件权限为所有者读写,其他用户只读
  3. 确认读写循环逻辑
    必须循环读取stdin直到EOF(read返回0),同时将读取到的数据分别写入stdout和目标文件:

    char buf[1024];
    ssize_t n;
    while ((n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
        write(STDOUT_FILENO, buf, n); // 输出到终端
        write(fd, buf, n); // 写入文件
    }
    

    注意要检查read/write的返回值,处理错误情况。

  4. 添加错误提示
    在open、read、write、close调用失败时,向stderr输出错误信息,方便定位问题。

示例正确实现片段

以下是一个简化的符合预期的tee实现(基于系统调用):

#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

#define BUF_SIZE 1024

int main(int argc, char *argv[]) {
    int fd;
    ssize_t numRead;
    char buf[BUF_SIZE];

    if (argc != 2) {
        const char *errMsg = "Usage: ./tee filename\n";
        write(STDERR_FILENO, errMsg, strlen(errMsg));
        exit(EXIT_FAILURE);
    }

    fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        const char *errMsg = "Failed to open target file\n";
        write(STDERR_FILENO, errMsg, strlen(errMsg));
        exit(EXIT_FAILURE);
    }

    while ((numRead = read(STDIN_FILENO, buf, BUF_SIZE)) > 0) {
        if (write(STDOUT_FILENO, buf, numRead) != numRead) {
            const char *errMsg = "Error writing to stdout\n";
            write(STDERR_FILENO, errMsg, strlen(errMsg));
            exit(EXIT_FAILURE);
        }
        if (write(fd, buf, numRead) != numRead) {
            const char *errMsg = "Error writing to file\n";
            write(STDERR_FILENO, errMsg, strlen(errMsg));
            exit(EXIT_FAILURE);
        }
    }

    if (numRead == -1) {
        const char *errMsg = "Error reading from stdin\n";
        write(STDERR_FILENO, errMsg, strlen(errMsg));
        exit(EXIT_FAILURE);
    }

    if (close(fd) == -1) {
        const char *errMsg = "Error closing file\n";
        write(STDERR_FILENO, errMsg, strlen(errMsg));
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}

内容的提问来源于stack exchange,提问作者Chih-Hao Liu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 07:09:54