时间:2020年1月19号
用途:自我学习
目录
重定向和管道
这里先说下与重定向和管道密切相关的一个内容,那就是标准输入输出。
1.标准输入和输出:
IO:
I:从外部设备输出到内存;
O:从内存输出到外部设备。
标准输入和标准输出:
用于IO的外部设备(逻辑上的外部设备)。在Linux中,一切设备皆文件。因此标准输入标准输出更具体的含义是文件。
当我们使用文件描述符进行操作时,需要操作标准输入、标准输出、标准错误,可以包含如下头文件:
#include <unistd.h>
这个头文件中定义了标准设备:
/* Standard file descriptors. /
#define STDIN_FILENO 0 / Standard input. / 默认接受来自键盘的输入
#define STDOUT_FILENO 1 / Standard output. / 默认输出到终端窗口
#define STDERR_FILENO 2 / Standard error output. */ 默认输出到终端窗口
每当启动一个进程的时候,都会有一个默认的stdin和stdout生成,默认情况下,stdin就是键盘,是stdout就是显示器。
比如C语言中:
printf("这是标准输出\n");
//相当于
fprintf(stdout,"这是标准输出\n");
int x;
scanf("%d",&x);
//相当于
fscanf(stdin,"%d",&x);
如何使用标准IO库中的文件操作可参考文章:https://blog.csdn.net/rikeyone/article/details/88668443
2.重定向
重定向:大多数命令行解释器都具有重定向的功能(Unix、Dos、包括我现在学习的UEFI系统中的shell).
输入重定向:可以使程序能够使用文件代替键盘作为输入;
输出重定向:可以使程序能够使用文件代替屏幕作为输出。
文件结尾:操作系统需要某种方式来判断每个文件起始和结束的位置,一般有两种方法:一种是检测文件结尾的的一个特殊字符来进行标识,另一种是让操作系统存储文件大小的信息来进行判断。
对于这两种不同的方法,C的处理方式是让getchar()函数在到达文件结尾时返回一个特殊值,而不管操作系统采用哪种方法,赋予该值得名称是EOF(end of file),其值一般是-1,在stdio.h文件中定义。
可以使用下列程序进行判断是否读入到文件结尾:
while((ch=getchar())!=EOF) // 当ch为EOF时停止
这里需要注意一个问题,EOF是不可输出字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于EOF时,表示读入的已不是正常的字符而是文件结束符,但这适用对文本文件的读写。在二进制文件中,信息都是以数值方式存在的。EOF的值可能就是所要处理的二进制文件中的信息。这就出现了需要读入有用数据却被处理为“文件结束“的情况。为了解决这个问题,C提供了一个feof()函数,可以用它来判断文件是否结束。feof(fp)用于测试fp所指向的文件的当前状态是否为“文件结束”。如果是,函数则返回的值是1(真),否则为0(假)。此段摘于链接处文章,详细可参考文章:https://blog.csdn.net/bingqing07/article/details/5785080
2.1输入重定向
<
:从文件中读取数据
在Windows下需要一个已经编译好的程序test.exe及编写好的符合输入的test.txt文本,则可在DOS下直接使用(注:需这2个文件在同一目录,且DOS已经切换到该目录,否则需要指定路径)
test.exe < test.txt
< 符号是Unix、Linux(和DOS)的重定向运算符,该运算符把test.txt文件与stdin流关联起来,将该文件的内容引导至test.exe程序,程序本身并不知道也不关心输入时来自于文件还是键盘,它只知道的一切就是向它传送了一个字符流,然后进行相应处理,直到遇到文件结尾。
2.2输出重定向
>
:把stdout重定向到文件,文件内容会被覆盖
>>
:把stdout重定向到文件,文件内容不会被覆盖,而是在原有基础上追加内容
2>
:把stderr重定向到文件,进行覆盖。
2>>
:把stderr重定向到文件,进行追加。
&>
or>&
or2>&1
:把stdout和stderr作为同一个数据流重定向到文件
&>>
:把stdout和stderr一起进行重定向追加了
(程序命令;程序命令;...)
:配合上述格式,可以合并多个程序命令的stdout和stderr来覆盖或追加
注意:stdout和stderr分开输出到不同文件时,必须是stdout在前,stderr在后,也就是2>
、2>>
、2>&1
都需要在正确输出的后面。
具体的写法如下:
command > /path/to/file.out 2> /path/to/error.out command >> /path/to/file.all.out 2>>/path/to/error.out command > /path/to/file.all.out 2>&1 == command &> /path/to/file.all.out == command >& /path/to/file.all.out
在Windows下需要一个已经编译好的程序OutPutTest.exe则可在DOS下直接使用.
OutPutTest.exe > OutPutTest.txt
程序的输出结果不会在DOS下打印,而会直接存入OutPutTest.txt 中。符号将输出重定向到该文件,该重定向将stdout从显示设备重定向到OutPutTest.txt文本文件,
注:用 >
输出重定向时若没有对应的输出文件时,会自动创建,若已存在,会删除原文件并建立新文件代替。
3.管道:
管道就是一个进程与另一个进程之间通信的通道,它通常是用作把一个进程的输出通过管道连接到另一个进程的输入。它是半双工运作的,想要同时双向传输需要使用两个管道。管道又可以分为匿名管道和命名管道,而shell中使用到的是匿名管道,所以这里仅简单描述匿名管道。
例如命令 ls | grep main.c
,使用了管道来连接了两条命令来执行,能够快速地让我们知道当前目录下是否有 main.c
文件。
管道的本质是内存中的缓冲区,可以看作是打开到内存中的文件。所以需要使用两个文件描述符来索引它,一个表示读端,一个表示写端。并且规定,数据只能从读端读取、只能往写端写入。
管道符号“|
”用来连接命令:
command 1 | command 2 | command 3
上述是将command 1的stdout 发送给command 2的stdin,command 2 的stdout 发送给command 3的stdin,最后command 3的会在当前shell进程的子shell进程中执行出来。
4.实例:
4.1输入重定向
test.c:
#include <stdio.h>
#if 1
int main()
{
char ch;
while ((ch = getchar()) != EOF) //读取输入字符
{
putchar(ch); //输出字符
}
putchar('\n');
return 0;
}
#endif
test.txt:
This is an input redirection test.
这是一个输入重定向测试
运行结果:
4.2输出重定向
OutPutTest.c
#include <stdio.h>
#if 1
int main()
{
printf("This is an output redirection test instense\n");
return 0;
}
#endif
运行结果:
4.3管道
OutPutTest.c:
#include <stdio.h>
#if 1
int main()
{
printf("This is an output redirection test instense\n");
return 0;
}
#endif
InputTest.c
#include <stdio.h>
#if 1
int main()
{
char ch;
printf("This is ths input instense\n");
while ((ch = getchar()) != EOF) //读取输入字符
{
putchar(ch); //输出字符
}
putchar('\n');
return 0;
}
#endif
运行结果: