我正在进行一项任务,我们将重新创建cat命令的三个开关,-n / -T / -E。我们要编译并输入两个参数,即开关和文件名。我将文本文件内容存储到缓冲区中。
int main(int argc, char *argv[]){
int index = 0;
int number = 1;
int fd, n, e, t;
n = e = t = 0;
char command[5];
char buffer[BUFFERSIZE];
strcpy(command, argv[1]);
fd = open(argv[2], O_RDONLY);
if( fd == -1)
{
perror(argv[2]);
exit(1);
}
read(fd, buffer,BUFFERSIZE);
if( !strcmp("cat", command)){
printf("%s\n", buffer);
}
else if( !strcmp("-n", command)){
n = 1;
}
else if( !strcmp("-E", command)){
e = 1;
}
else if( !strcmp("-T", command)){
t = 1;
}
else if( !strcmp("-nE", command) || !strcmp("-En", command)){
n = e = 1;
}
else if( !strcmp("-nT", command) || !strcmp("-Tn", command)){
n = t = 1;
}
else if( !strcmp("-ET", command) || !strcmp("-TE", command)){
t = e = 1;
}
else if( !strcmp("-nET", command) || !strcmp("-nTE", command) ||
!strcmp("-TnE", command) || !strcmp("-EnT", command) ||
!strcmp("-ETn", command) || !strcmp("-TEn", command)){
n = e = t = 1;
}
else{
printf("Invalid Switch Entry");
}
if(n){
printf("%d ", number++);
}
while(buffer[index++] != '\0' && ( n || e || t)){
if(buffer[index] == '\n' && e && n){
printf("$\n%d ", number++);
}
else if(buffer[index] == '\n' && e){
printf("$\n");
}
else if(buffer[index] == '\t' && t){
printf("^I");
}
else if(buffer[index] == '\n' && n){
printf("\n%d ", number++);
}
else {
printf("%c", buffer[index]);
}
}
printf("\n");
close(fd);
return 0;
}
除非我尝试使用-n命令,否则一切都很完美。它增加了一条额外的新线。我使用的文本文件
hello
hello
hello world!
而不是
1 hello
2 hello
3 hello world!
它将打印出来:
1 hello
2 hello
3 hello world!
4
由于某种原因,它增加了世界之后的额外线!
我错过了一些简单的东西吗?
答案 0 :(得分:1)
这可能无法解决您的问题,但我没有看到任何代码将终止空字符放在buffer
中。尝试:
// Reserve one character for the null terminator.
ssize_t n = read(fd, buffer, BUFFERSIZE-1);
if ( n == -1 )
{
// Deal with error.
printf("Unable to read the contents of the file.\n");
exit(1); //???
}
buffer[n] = '\0';
答案 1 :(得分:0)
您实施的三个cat
选项具有不同的"模式":
-T
替换一个字符(没有写标签); -E
预先添加一个带有附加输出的字符(仍然会写入换行符); -n
在每行前面加上额外的输出。您可以直接处理前两种模式。第三种模式需要来自该字符的信息:在文件开头和读取换行字符后开始一个新行。所以你需要一个标志来跟踪它。
(您的代码在找到换行符之后打印一个行号。这意味着您必须明确地处理第一行,并在结尾处获得一行太多的行。毕竟,一个带{的文件{1}}行包含n
个换行符,您可以打印n
行号。)
其他问题:
n + 1
返回读取的字节数或错误代码。您可以将该号码用作read
。index
条件中包含index
,这意味着您在循环中检查的字符后面查看字符,这可能是空字符。您还将错过文件中的第一个字符。while
,直到您读取的字节数少于read
,但在这种情况下最简单的方法是读取另一个字节并处理它。BUFFERSIZE
。switch
吗?查找减号作为第一个字符,然后逐个字母,设置标记并打印错误消息。strcmps
复制到argv[1]
;你只是检查它。而且你引入了一个错误来源:如果第二个参数超过4个字符,你将得到未定义的行为,很可能是崩溃。command
,而不是argv[1]
。将此(无解析标记)付诸实践:
argv[2]
修改:如果您只能使用Unix FILE *f = fopen(argv[2], "r");
int newline = 1; // marker for line numbers
// Error checking
for (;;)
{
int c = fgetc(f); // read one character
if (c == EOF) break; // terminate loop on end of file
if (newline) {
if (n) printf("%5d ", number++);
newline = 0;
}
if (c == '\n') {
newline = 1;
if (e) putchar('$');
}
if (c == '\t' && t) {
putchar('^');
putchar('I');
} else {
putchar(c);
}
}
fclose(f);
,open
和close
,您仍然可以使用上述方法。您需要一个额外的循环,使用read
读取特定大小的块。 read
函数返回读取的字节值。如果小于要求的字节数,请停止循环。
下面的示例添加了一个允许连接多个文件的附加循环。
read