如何用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>的要求。 - 按块读取文件:比逐字符读取更高效,同时处理缓冲区中的完整行和剩余的不完整行。
- 字段提取逻辑:
- 对每行先找到第一个
:,提取前面的用户名。 - 从第一个
:后开始计数,找到第6个:的位置,提取后面的Shell路径。 - 跳过格式不符合的行,避免程序崩溃。
- 对每行先找到第一个
- 错误处理:用
write输出错误信息,不依赖printf。
内容的提问来源于stack exchange,提问作者Mozart
相关产品推荐
相关产品推荐

