linux/unix系统编程手册 4章习题

作为一个咸鱼废了好久,期中很多考试,复习有点无聊,开始之前准备看的linux/unix系统编程手册

另外去官网找源代码和头文件,make失败,尝试了一会儿就放弃了,毕竟影响不大

4-1

tee命令是从标准输入中读取数据,直至文件结尾,随后将数据写入标准输出和命令行参数所指定的文件。请使用I/O系统调用实现tee命令。默认情况下,若已存在与命令行参数指定文件名同名的文件,tee命令将其覆盖。或者,当使用-a命令时,则在同名文件后面追加数据。

tee –help

1
2
3
4
5
6
7
8
9
10
$ tee --help
用法:tee [选项]... [文件]...
将标准输入复制到每个指定文件,并显示到标准输出。

-a, --append 内容追加到给定的文件而非覆盖
-i, --ignore-interrupts 忽略中断信号
-p diagnose errors writing to non pipes
--output-error[=MODE] set behavior on write error. See MODE below
--help 显示此帮助信息并退出
--version 显示版本信息并退出

实现这个命令主要是这章介绍的 通用I/O模型 中的open(),close(),read(),write().
另外使用到了附录中的getopt();

另外感觉自己只有看到习题才能起看书的兴致,果然以后看书先看题再看书也不错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <unistd.h>
#include <stdio.h>
#include<fcntl.h>
#include<sys/stat.h>

struct teeConfigStruct
{
int a;
char *outputPath;
int outputFd;
} teeConfig;

void getArgs(int argc, char *const argv[])
{
int opt;
if ((opt = getopt(argc, argv, "a")) != -1)
{
teeConfig.a = 0;
switch (opt)
{
case 'a':
printf("追加模式\n");
teeConfig.a = 1;
break;
default:
printf("参数错误\n");
_exit(0);
break;
}
}
if (argc - optind < 1)
{
printf("参数太少\n");
_exit(0);
}
teeConfig.outputPath = argv[optind];
printf("输出路径 %s \n", teeConfig.outputPath);
}

int main(int argc, char * const argv[]){
getArgs(argc, argv);
int outputFileFlag;
if(teeConfig.a == 1)
{
outputFileFlag =O_RDWR | O_CREAT | O_APPEND;
}
else
{
outputFileFlag = O_RDWR | O_CREAT | O_TRUNC;
}
teeConfig.outputFd = open(teeConfig.outputPath, outputFileFlag, 0777);
if (teeConfig.outputFd == -1)
{
printf("无法打开输出文件!\n");
_exit(0);
}
char buff;
while (read(STDIN_FILENO, &buff, 1) > 0)
{
printf("%c", buff);
if (write(teeConfig.outputFd, &buff, 1) == -1)
{
printf("无法写入输出文件!\n");
_exit(0);
}
}
if (close(teeConfig.outputFd) == -1)
{
printf("无法关闭输出文件!\n");
_exit(0);
}
}

4-2

编写一个类似于cp命令的程序,当使用该程序复制一个包含空洞的文件时,能够使得目标文件和源文件内容保持一致

这个程序思路比较简单,读取源文件的一个字符,如果是0的话,使用lseek右移一个文件偏移量。否则将字符写入目标文件中。

文件空洞 :当文件的偏移量大于文件的当前长度时,文件结尾到新写入数据之间的空间称为文件空洞。读取文件空洞的内容会返回以0填充的缓冲区。

     “空洞是否占用磁盘空间由文件系统决定”
     “如果空洞的边界落在块内,而非恰好落在块的边界上,则会分配一个完整的块来存储数据,块中与空洞相关的部分则以空字节填充”—-书本提示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <unistd.h>
#include <stdio.h>
#include<fcntl.h>
#include<sys/stat.h>

struct copyConfigStruct{
int inputFd;
int outputFd;
char *intputPath;
char *outputPath;
}copyConfig;

int main(int argc, char *const argv[])
{
if(argc <3)
{
printf("参数过少\n");
_exit(0);
}
copyConfig.intputPath = argv[1];
copyConfig.outputPath = argv[2];
copyConfig.inputFd = open(copyConfig.intputPath,O_RDONLY);
if(copyConfig.inputFd == -1)
{
printf("打开文件失败\n");
_exit(0);
}
copyConfig.outputFd = open(copyConfig.outputPath, O_RDWR|O_TRUNC|O_CREAT, 0777);
if(copyConfig.outputFd == -1){
printf("输出文件打开失败!\n");
_exit(0);
}
char buff;
while( read(copyConfig.inputFd, &buff, 1) > 0 ){
if (buff == 0){
if(lseek(copyConfig.outputFd, 1, SEEK_CUR) == -1){
printf("跳过空洞失败!\n");
_exit(0);
}
}
else if(write(copyConfig.outputFd, &buff, 1) == -1){
printf("写入文件失败!\n");
_exit(0);
}
}
close(copyConfig.inputFd);
close(copyConfig.outputFd);
}