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

如何用C语言读取/etc/passwd并输出用户名与Shell路径?

解决读取/etc/passwd提取用户名与Shell路径的问题

现有代码的问题

  • 缺少open、read、write所需的头文件:<unistd.h>和<fcntl.h>,编译时会出现函数未声明的错误。
  • strlen(buff - 17)属于非法操作:buff是未初始化的局部数组,直接偏移地址会访问非法内存,触发未定义行为。
  • 没有实现字段提取逻辑:当前代码只是逐字符输出整个文件内容,完全没处理/etc/passwd的字段分隔规则。
  • printf的使用存在风险:仅声明原型但未链接标准库的话可能无法正常工作,建议改用write输出错误信息以避免依赖。

正确实现代码

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

#define BUFFERSIZE 4096

int main(void) {
    int fd;
    char buff[BUFFERSIZE];
    ssize_t bytes_read;
    char *line_start, *colon;
    int colon_count;

    fd = open("/etc/passwd", O_RDONLY);
    if (fd < 0) {
        const char err_msg[] = "Error opening file\n";
        write(STDOUT_FILENO, err_msg, sizeof(err_msg) - 1);
        return -1;
    }

    // 按块读取文件内容
    while ((bytes_read = read(fd, buff, BUFFERSIZE - 1)) > 0) {
        buff[bytes_read] = '\0'; // 确保缓冲区以null结尾
        line_start = buff;

        // 处理每一行
        while ((colon = strchr(line_start, '\n')) != NULL) {
            *colon = '\0'; // 将换行符替换为null,分割出当前行
            colon_count = 0;
            char *current = line_start;

            // 提取第一个字段(用户名)
            char *username = current;
            while (*current != ':' && *current != '\0') {
                current++;
            }
            if (*current != ':') {
                line_start = colon + 1;
                continue; // 格式错误的行,跳过
            }
            *current = '\0'; // 截断用户名部分

            // 寻找第6个冒号
            current++; // 跳过第一个冒号
            while (current != '\0' && colon_count < 5) {
                if (*current == ':') {
                    colon_count++;
                }
                current++;
            }
            if (colon_count != 5 || *current == '\0') {
                line_start = colon + 1;
                continue; // 格式错误的行,跳过
            }
            char *shell = current;

            // 输出结果:用户名:shell路径
            write(STDOUT_FILENO, username, strlen(username));
            write(STDOUT_FILENO, ":", 1);
            write(STDOUT_FILENO, shell, strlen(shell));
            write(STDOUT_FILENO, "\n", 1);

            line_start = colon + 1; // 移动到下一行起始位置
        }

        // 处理缓冲区中剩余的不完整行(如果有的话)
        size_t remaining = strlen(line_start);
        if (remaining > 0) {
            memmove(buff, line_start, remaining);
            buff[remaining] = '\0';
            // 下一次读取会追加到这个剩余内容后面
        } else {
            buff[0] = '\0';
        }
    }

    // 处理最后剩余的不完整行(如果文件末尾没有换行符)
    if (strlen(buff) > 0) {
        char *current = buff;
        char *username = current;
        while (*current != ':' && *current != '\0') {
            current++;
        }
        if (*current != ':') {
            close(fd);
            return 0;
        }
        *current = '\0';

        current++;
        int colon_count = 0;
        while (current != '\0' && colon_count < 5) {
            if (*current == ':') {
                colon_count++;
            }
            current++;
        }
        if (colon_count != 5 || *current == '\0') {
            close(fd);
            return 0;
        }
        char *shell = current;

        write(STDOUT_FILENO, username, strlen(username));
        write(STDOUT_FILENO, ":", 1);
        write(STDOUT_FILENO, shell, strlen(shell));
        write(STDOUT_FILENO, "\n", 1);
    }

    close(fd);
    return 0;
}

代码说明

  • 依赖头文件:<string.h>用于字符串处理,<unistd.h>提供read/write/close,<fcntl.h>提供open和O_RDONLY常量,均符合不使用<stdio.h>/<stdlib.h>的要求。
  • 按块读取文件:比逐字符读取更高效,同时处理缓冲区中的完整行和剩余的不完整行。
  • 字段提取逻辑:
    1. 对每行先找到第一个:,提取前面的用户名。
    2. 从第一个:后开始计数,找到第6个:的位置,提取后面的Shell路径。
    3. 跳过格式不符合的行,避免程序崩溃。
  • 错误处理:用write输出错误信息,不依赖printf。

内容的提问来源于stack exchange,提问作者Mozart

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 08:05:26