rwl程序在bash循环中运行的输出分析及终止代码修改咨询
问题分析与解决方案
一、原程序的输出内容
首先注意原代码存在语法错误:read((0, buf, 2); 应为 read(0, buf, 2);,否则无法编译运行。假设修正该错误后,分析如下:
假设fileA的内容为两行01234,即字节序列为:0 1 2 3 4 \n 0 1 2 3 4(共11字节,索引0~10)。执行while rwl; do :; done < fileA时,每次调用rwl的行为如下:
- 第1次调用:从偏移0读取2字节
01并输出,lseek将文件指针移至偏移3;程序返回0,循环继续。 - 第2次调用:从偏移3读取2字节
34并输出,lseek将指针移至偏移6;程序返回0,循环继续。 - 第3次调用:从偏移6读取2字节
01并输出,lseek将指针移至偏移9;程序返回0,循环继续。 - 第4次调用:从偏移9读取2字节
34并输出,lseek将指针移至偏移12(超出文件末尾);程序返回0,循环继续。 - 第5次及之后调用:文件指针已在EOF位置,
read返回0,此时buf保留上次的34,程序仍执行write输出34,且始终返回0,导致外层while循环无限执行,持续输出34。
最终输出为:01340134343434...(无限循环输出34)
二、修改源码使命令正常终止的方法
原程序的核心问题是未检查read返回值,且始终返回0的退出状态,导致外层while循环无法终止。以下是两种可行的修改方案:
方案1:单次读取,检查返回值
修改程序,在read失败(返回0或-1)时返回非0状态,同时只写入实际读取的字节数:
#include <unistd.h> int main() { char buf[2]; ssize_t n_bytes = read(0, buf, 2); // 读取失败或到达EOF时,返回非0状态终止外层循环 if (n_bytes <= 0) { return 1; } lseek(0, 1, SEEK_CUR); write(1, buf, n_bytes); // 仅写入实际读取的字节数,避免垃圾数据输出 return 0; }
方案2:内部循环读取整个文件
若希望rwl一次性处理完整个文件,可在内部添加循环,但需注意在EOF时返回非0状态,避免外层while重复执行:
#include <unistd.h> int main() { char buf[2]; ssize_t n_bytes; while ((n_bytes = read(0, buf, 2)) > 0) { lseek(0, 1, SEEK_CUR); write(1, buf, n_bytes); } // 到达EOF时返回1,终止外层while循环;读取错误时返回0(可根据需求调整) return n_bytes == 0 ? 1 : 0; }
三、提问者之前修改失败的原因
提问者尝试添加while(read(0, buf, 2) > 0)循环但未成功,大概率是因为未在read返回0时让程序返回非0状态。例如,若仅添加内部循环但仍返回0,第一次调用rwl会读完文件并返回0,外层while会再次调用rwl,此时read返回0但程序仍返回0,导致循环无限执行。只有让程序在EOF时返回非0状态,才能让外层while正常终止。
内容的提问来源于stack exchange,提问作者Ozan Aykan
相关产品推荐
相关产品推荐

