《Linux Shell脚本攻略》一书中,关于重定向的理解与补充

 在个人学习《Linux Shell脚本攻略》第一章时,到第1.6节“玩转文件描述符及重定向”中,发现有一处言语不明(也或者是例子不当之处)。 

1 文件描述符

文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。在windows中,内核记录应用打开的对象,就是handle句柄,也是一个整数值,两者有相似之处。

在Linux中,在编写脚本的时候会频繁使用标准输入( stdin)、标准输出( stdout)和标准错误( stderr)。通过内容过滤将输出重定向到文件是我们平日里的基本任务之一。文件描述符是与某个打开的文件或数据流相关联的整数。文件描述符0、 1以及2是系统预留的,相当于每个进程的全局变量。

Linux Shell脚本攻略-重定向理解与补充

2 重定向试验与理解

于是开始按照示例来试。

~$ echo "A sample test" echo命令把这段文字输出到 stdout

A sample test          

~$ echo "A sample test to out.txt" > out.txt 

上面一行命令,把本来要输出到stdout文件(屏幕),重定向到磁盘文件out.txt中

~$ cat out.txt

A sample test to out.txt 显然是重定向成功了

~$ echo "A sample test append to out.txt" >> out.txt

上面一行命令,把本来要输出到stdout文件(屏幕),重定向到磁盘文件out.txt中,并且加到尾部

~$ cat out.txt

A sample test to out.txt  

A sample test append to out.txt

显然是重定向成功了,内容也成功的加到了尾部

前面这一部分非常简单。

~$ ls +abcd  故意让这个命令出错,出错信息会输出到stderr

ls: 无法访问 '+abcd': 没有那个文件或目录 出错信息

$ ls +abcd >stderr.txt

ls: 无法访问 '+abcd': 没有那个文件或目录 出错信息

~$ cat stderr.txt

这一行命令,什么也不会输出,因为出错信息是输出到stderr中的

~$ ls +abcd 2>stderr.txt

~$ cat stderr.txt

ls: 无法访问 '+abcd': 没有那个文件或目录

出错信息重定向到了stderr.txt中

重定向的命令语法是:cmd [参数] 文件描述符>文件

如果“文件描述符”不输入的法,默认是1,也就是stdout。比如:echo "a test" > out.txt, 相当于:echo "a test" 1> out.txt。所以上面的“ls +abcd 2>stderr.txt”才能把出错信息重定向到stderr.txt文件中。红字“2”就是指stderr。

3 多重定向命令的理解

Linux Shell脚本攻略-重定向理解与补充

如上图,执行“ls + 2>stderr.txt 1>stdout.txt”后,这个命令是想达到:stderr单独重定向到磁盘文件stderr.txt,将stdout重定向到另一个磁盘文件stdout.txt。结果:可以cat到stderr.txt有内容,但stdout.txt没有任何内容。

没有得到合适的观察结果,让人怀疑是错了?

没办法,自制了一个命令,C代码文件:redirection_test.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
    printf("This line out to stdout \n"); //输出到stdout
    perror("This line out to stderr "); //输出到stderr
    return 0;
}

使用“gcc redirection_test.c -o redirection_test.out”编译成可执行程序redirection_test.out。

$./redirection_test 2>stderr.txt 1>stdout.txt

这一行命令,故意让这个命令出错,出错信息会输出到stderr

$ cat stderr.txt

This line out to stderr : Success

$ cat stdout.txt

This line out to stdout

Linux Shell脚本攻略-重定向理解与补充

其实,脚本攻略上讲的没有错,只是我没用到合适的测试程序。“ls +”出错后,只向stderr输出信息,而没有向stdout输出信息,所以测不出来。

4 系统保留文件描述符

前面提到过:文件描述符0(stdin)、 1(stdout)以及2(stderr)是系统预留的,相当于每个进程的全局变量。

每个进程创建时,内核为进程打开的文件创建了一个文件描述符表,该表的每一条都记录了进程打开的文件,这个表格的索引序号就是文件描述。

Linux Shell脚本攻略-重定向理解与补充

那么,stdin、 stdout以及stderr,这三个妖怪在哪里呢?

Linux Shell脚本攻略-重定向理解与补充

原来是躲藏在"/dev"目录下面。看到没有,它们分别指向内核的“/proc/self/fd/0(0/1/2)”处。至此,我挖到了它们,感觉真相大白。

5 验证一下“/dev/stdout”的真身

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

#define WRITE_STRING "0123456789ABC\n"
#define LEN_OF_WRITE_STR strlen(WRITE_STRING)

int main(int argc,char *argv[])
{
    size_t write_len=0 ;
    write_len = write(2,WRITE_STRING,LEN_OF_WRITE_STR);

    if (write_len != LEN_OF_WRITE_STR)
    {
        printf("File : /dev/stdout write error\n") ;
        exit(1);
    }
    printf("Write %d bytes to /dev/stdout \n",(int)write_len) ;
    return 0;
}

使用“gcc main.c -o stdout_test.out”编译成可执行程序:stdout_test.out。

Linux Shell脚本攻略-重定向理解与补充

我得到了以下验证:

(1)stdout的序号是全局的,且默认打开的,因为这里我没有open动作。

(2)系统API函数write,把字符串写到“/dev/stdout”,意味着输出在屏幕上了。

仔细看看,上面的代码没有“/dev/stdout”,为何说是成功了呢?如果再想进一步验证,可用以下代码来替代前几行。

fd = open("/dev/stdout",O_WRONLY);
if (fd < 0)
{
    perror("perror: file open error ");
    exit(1);
}
write_len = write(fd,WRITE_STRING,LEN_OF_WRITE_STR);

结果是一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虎哥的世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值