【转】Linux shell IO重定向


Linux shell中的File Descripter可以理解为一个指向文件的指针。默认有三个FD:0,1,2。分别指向的是:Keyboard设备文件,Moniter设备文件,和Moniter设备文件。


Shell中还允许有3--9的FD,默认都没有打开,可以认为指向的为NULL。


可以通过以下命令查看打开的FD:
ls /proc/self/fd
返回的数字代表FD的值。

利用重定向可以为一个FD赋值,使其指向一个非NULL的文件,其实就是打开一个FD。


6>&1

可以理解为将FD6指针指向FD1指针指向的文件,即Moniter。这样,FD6和FD1就同时指向同一个文件:Moniter。

6>&-
可以理解为将FD6指针置为空值null,即关闭FD6。

一个重定向只在当前命令中有效。exec可以使IO重定向在当前shell中长期有效。

通过类似指针的特性,I/O重定向可以用来保存当前某个FD并在其后恢复。例如:

过滤stderr中的内容,屏蔽含有字符串“unused”的错误输出:


# 创建FD6,指向FD1指向的moniter。
exec 6>&1

# 运行command命令,将stdout重定向给FD6,再将stderr重定向给stdout。
# 这时,command有两个输出FD,
# 分别是FD1和FD6,FD1是错误信息,FD6是标准输出内容。
# 再将FD1错误信息通过pipe传给grep进行过滤,并将过滤后的内容重定向给FD2。
# 最后,将之前的FD6的内容重定向给FD1。
# 这样,这条命令有两个输出,FD1是command的标准输出内容,
# FD2是经过过滤的command的错误输出。
(command 2>&1 >&6 | grep -v unused >&2) 6>&1

# 关闭FD6。

exec 6>&- 



  • cmd1 |cmd2 : pipe,将cmd1 的标准输出作为cmd2 的标准输入
  • >file :将标准输出重定向到file
  • <file :将file作为标准输入
  • >>file :将标准输出重定向到file,如果file存在,append到文件中,即附加到文件的后面,而不是覆盖文件

    当cat不带参数的时候,表示使用标准输入作为输入,这允许在标准输入中键入相关的内容,下面将alias加入.bashrc作为最后一行 
    $ cat >> .bashrc 
      alias cdmnt='mount -t iso9660 /dev/sbpcd /cdrom' 
      ^D

  • >|file :强制将标准输出重定向到file,即使noclobber设置。当设置环境变量set –o noclobber,将禁止重定向到一个已经存在的文件中,避免文件被覆盖。
  • n >|file :强制将文件描述符n重定向到file,即使noclobber打开
  • <>file :将file作为标准输入和标准输出。通常用于设备文件(/dev下面的文件),底层系统程序员可用之测试设备驱动,其他的很少用。
  • n <>file :将file作为文件描述符n的输入和输出
  • <<label :Here-document; see text 。将shell的标准输入作为命令的输入,直到行中之包含label。这中间的输入成为here-document。下面是一个例子。我们让人使用cat >> file的方式,通过标准输入在文件中附加内容。

    $ cat >> msgfile << . #这里<<.表明以.为结束。因此无需使用^D,而改用. 
      > this is the text of 
      > our message. 
      > .   #这里表示结束。则msgfile中增加了两行this is…和our message. 
    MACHINE="i586" 
    OS="linux-gnu" 
    CC="gcc" 
    cat > $file <
    Machine: $MACHINE 
    OS: $OS 
    Compiler: $CC 
    EOF 
    查看:cat $file,这里给出正常结构 
    Machine: i586 
    OS: linux-gnu 
    Compiler: gcc 
    如果在EOF加上单引号,或者双引号如下 
    cat > $file <<'EOF' 
    则不解析$CC的内容,文件内容如下 
    Machine: $MACHINE 
    OS: $OS 
    Compiler: $CC 
    如果使用<<-,如下,则删除所有行中前面打头的> tab<这样在脚本的书写上会比较适合阅读 ,例如上面的例子可以写为: 
    cat > $file <<-EOF 
        Machine: $MACHINE 
        OS: $OS 
        Compiler: $CC 
        EOF

  • n>file :将文件描述符n重定向到file
  • n :将file作为文件描述符的输入
  • n>>file :将文件描述符n的输出重定向到file,如果file存在,将输出append到文件后面
  • n>& :将标准输出复制到文件描述符n(Duplicate standard output to file descriptor n)
  • n<& :从文件描述符n复制标准输入(Duplicate standard input from file descriptor n)
  • n>&m :文件描述字n将一个copy至文件描述字m(File descriptor n is made to be a copy of the output file descriptor)
  • n<&m :文件描述字n作为文件描述字m中的一个拷贝(File descriptor n is made to be a copy of the input file descriptor)
  • &>file : 将标准输出和标准错误输出定向至文件file
  • <&- : 关闭标准输入
  • >&- : 关闭标准输出
  • n>&- : 关闭文件描述字作为输出(Close the output from file descriptor n)
  • n<&- :关闭文件描述字作输入(Close the input from file descriptor n)
  • n>&word: If n is not specified, the standard output (file descriptor 1) is used. If the digits in word do not specify a file descriptor open for output, a redirection error occurs. As a special case, if n is omitted, and word does not expand to one or more digits, the standard output and standard error are redirected as described previously.
  • n<&word : If word expands to one or more digits, the file descriptor denoted by n is made to be a copy of that file descriptor. If the digits in word do not specify a file descriptor open for input, a redirection error occurs. If word evaluates to -, file descriptor n is closed. If n is not specified, the standard input (file descriptor 0) is used.
  • n>&digit- : Moves the file descriptor digit to file descriptor n, or the standard output (file descriptor 1) if n is not specified.
  • n<&digit- : Moves the file descriptor digit to file descriptor n, or the standard input (file descriptor 0) if n is not specified. digit is closed after being duplicated to n.
文件描述符

  文件描述符在bash中比较少用,从0开始用户表示进行的数据流,0表示标准输入,1表示标准输出,2表示标注错误输出,其他从3开始。最为常用的场景是将错误消息输出到某个文件,可以加上2>file 到我们的命令中。

  我们来看下面一个脚本的例子:

command   > logfile 2>&1 &

  >logfile,表示command的标准输出重定向至文件logfile中,2>&1,匹配n>&m,表示文件描述字2(command的标准错误输出)将copy一份采用文件描述字1(即标准输出),由于标准输出已经重定向logfile,这份copy也见将重定向至文件lofgile。我们可以用“abcd > logfile 2>&1 &”来验证这个效果。最后&表示后台运行的方式。这样命令表示在后台运行command,而它的标准输出和错误输出均重定向到logfile文件中。下面可达到类似的效果:

command 2>&1 | tee logfile &

  错误输出同样适用标准输出,通过pipe方式,见他们作为输入执行tee logfile。tee命令将它的标准输入copy至他的标准标准输出以及参数所带的文件中。和上面的命令不一眼这里即会在stdout 和logfile中同时输出。

其他文件描述字的重定向,例如<&n,通常用于从多个文件中读入或者写出。

<&- ,表示强制关闭标准输入 
>&- ,表示强制关闭标准输出 
1> ,等同于> 
0< ,等同于<

linux shell数据重定向(输入重定向与输出重定向)详细分析

在了解重定向之前,我们先来看看linux 的文件描述符。

linux文件描述符:可以理解为linux跟踪打开文件,而分配的一个数字,这个数字有点类似c语言操作文件时候的句柄,通过句柄就可以实现文件的读写操作。 用户可以自定义文件描述符范围是:3-num,这个最大数字,跟用户的:ulimit –n 定义数字有关系,不能超过最大值。

 

linux启动后,会默认打开3个文件描述符,分别是:标准输入standard input 0,正确输出standard output 1,错误输出:error output 2

以后打开文件后。新增文件绑定描述符 可以依次增加。 一条shell命令执行,都会继承父进程的文件描述符。因此,所有运行的shell命令,都会有默认3个文件描述符。

 

对于任何一条linux 命令执行,它会是这样一个过程:

image

一个命令执行了:

先有一个输入:输入可以从键盘,也可以从文件得到

命令执行完成:成功了,会把成功结果输出到屏幕:standard output默认是屏幕

命令执行有错误:会把错误也输出到屏幕上面:standard error默认也是指的屏幕

 

文件输入输出由追踪为一个给定的进程所有打开文件的整数句柄来完成。这些数字值就是文件描述符。最为人们所知的文件米描述符是 stdinstdout 和stderr,文件描述符的数字分别是0,1和2。这些数字和各自的设备是保留的。一个命令执行前,先会准备好所有输入输出,默认分别绑定(stdin,stdout,stderr),如果这个时候出现错误,命令将终止,不会执行。命令解析过程,可以参考:Linux Shell 通配符、元字符、转义符使用实例介绍

 

这些默认的输出,输入都是linux系统内定的,我们在使用过程中,有时候并不希望执行结果输出到屏幕。我想输出到文件或其它设备。这个时候我们就需要进行输出重定向了。

 

linux shell下常用输入输出操作符是:

1.  标准输入   (stdin) :代码为 0 ,使用 < 或 << ; /dev/stdin -> /proc/self/fd/0   0代表:/dev/stdin 
2.  标准输出   (stdout):代码为 1 ,使用 > 或 >> ; /dev/stdout -> /proc/self/fd/1  1代表:/dev/stdout
3.  标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ; /dev/stderr -> /proc/self/fd/2 2代表:/dev/stderr

 

  • 输出重定向:

格式:

command-line1 [1-n] > file或文件操作符或设备

上面命令意思是:将一条命令执行结果(标准输出,或者错误输出,本来都要打印到屏幕上面的)  重定向其它输出设备(文件,打开文件操作符,或打印机等等)1,2分别是标准输出,错误输出。

实例:

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
#显示当前目录文件 test.sh test1.sh test1.sh实际不存在
[chengmo@centos5 shell]$ ls  test .sh test1.sh
ls : test1.sh: 没有这个文件和目录
test .sh
 
#正确输出与错误输出都显示在屏幕了,现在需要把正确输出写入suc.txt
# 1>可以省略,不写,默认所至标准输出
[chengmo@centos5 shell]$ ls  test .sh test1.sh 1>suc.txt
ls : test1.sh: 没有这个文件和目录
[chengmo@centos5 shell]$ cat  suc.txt
test .sh
 
#把错误输出,不输出到屏幕,输出到err.txt
[chengmo@centos5 shell]$ ls  test .sh test1.sh 1>suc.txt 2>err.txt
[chengmo@centos5 shell]$ cat  suc.txt err.txt
test .sh
ls : test1.sh: 没有这个文件和目录
#继续追加把输出写入suc.txt err.txt  “>>”追加操作符
[chengmo@centos5 shell]$ ls  test .sh test1.sh 1>>suc.txt 2>>err.txt
 
#将错误输出信息关闭掉
[chengmo@centos5 shell]$ ls  test .sh test1.sh 2>&-
test .sh
[chengmo@centos5 shell]$ ls  test .sh test1.sh 2> /dev/null
test .sh
#&[n] 代表是已经存在的文件描述符,&1 代表输出 &2代表错误输出 &-代表关闭与它绑定的描述符
#/dev/null 这个设备,是linux 中黑洞设备,什么信息只要输出给这个设备,都会给吃掉
 
#关闭所有输出
[chengmo@centos5 shell]$ ls  test .sh test1.sh  1>&- 2>&-
#关闭 1 ,2 文件描述符
[chengmo@centos5 shell]$ ls  test .sh test1.sh  2> /dev/null  1> /dev/null
#将1,2 输出转发给/dev/null设备
[chengmo@centos5 shell]$ ls  test .sh test1.sh > /dev/null  2>&1
#将错误输出2 绑定给 正确输出 1,然后将 正确输出 发送给 /dev/null设备  这种常用
<p>[chengmo@centos5 shell]$ ls  test .sh test1.sh &> /dev/null
#& 代表标准输出 ,错误输出 将所有标准输出与错误输出 输入到/dev/null文件
< /p >

 

 

注意:

1、shell遇到”>”操作符,会判断右边文件是否存在,如果存在就先删除,并且创建新文件。不存在直接创建。 无论左边命令执行是否成功。右边文件都会变为空。

2、“>>”操作符,判断右边文件,如果不存在,先创建。以添加方式打开文件,会分配一个文件描述符[不特别指定,默认为1,2]然后,与左边的标准输出(1)或错误输出(2) 绑定。

3、当命令:执行完,绑定文件的描述符也自动失效。0,1,2又会空闲。

4、一条命令启动,命令的输入,正确输出,错误输出,默认分别绑定0,1,2文件描述符。

5、一条命令在执行前,先会检查输出是否正确,如果输出设备错误,将不会进行命令执行

  • 输入重定向

格式:

command-line [n] <file或文件描述符&设备

将然有,命令默认从键盘获得的输入,改成从文件,或者其它打开文件以及设备输入。执行这个命令,将标准输入0,与文件或设备绑定。将由它进行输入。

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[chengmo@centos5 shell] # cat > catfile
testing
cat  file  test
#这里按下 [ctrl]+d 离开
#从标准输入【键盘】获得数据,然后输出给catfile文件
 
[chengmo@centos5 shell]$ cat >catfile < test .sh
#cat 从test.sh 获得输入数据,然后输出给文件catfile
 
 
[chengmo@centos5 shell]$ cat >catfile <<eof
test  a file
test !
eof
 
#<< 这个连续两个小符号, 他代表的是『结束的输入字符』的意思。这样当空行输入eof字符,输入自动结束,不用ctrl+D

 

 

  • exec绑定重定向

格式:

exec 文件描述符[n] <或> file或文件描述符或设备

在上面讲的输入,输出重定向 将输入,输出绑定文件或设备后。只对当前那条指令是有效的。如果需要在绑定之后,接下来的所有命令都支持的话。就需要用exec命令

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[chengmo@centos5 shell]$ exec  6>&1
#将标准输出与fd 6绑定
 
[chengmo@centos5 shell]$ ls   /proc/self/fd/ 
0  1  2  3  6
#出现文件描述符6
 
[chengmo@centos5 shell]$ exec  1>suc.txt
#将接下来所有命令标准输出,绑定到suc.txt文件(输出到该文件)
 
[chengmo@centos5 shell]$ ls  -al
#执行命令,发现什么都不返回了,因为标准输出已经输出到suc.txt文件了
 
[chengmo@centos5 shell]$ exec  1>&6
#恢复标准输出
 
 
[chengmo@centos5 shell]$ exec  6>&-
#关闭fd 6描述符
 
[chengmo@centos5 ~]$ ls  /proc/self/fd/
0  1  2  3

说明:使用前先将标准输入保存到文件描述符6,这里说明下,文件描述符默认会打开0,1,2 还可以使用自定义描述符 。然后对标准输出绑定到文件,接下来所有输出都会发生到文件。 使用完后,恢复标准的输出,关闭打开文件描述符6。

有趣事情:

可能有朋友会这样用:exec 1>suc.txt ,接下来所有输出都绑定到suc.txt 文件,那么怎么样恢复原来的呢? 试试你就会发现问题所在……

  • 复杂一点实例
1
2
3
4
5
6
7
8
9
10
11
exec  3<> test .sh;
#打开test.sh可读写操作,与文件描述符3绑定
 
while  read  line<&3
  do
     echo  $line;
done
#循环读取文件描述符3(读取的是test.sh内容)
exec  3>&-
exec  3<&-
#关闭文件的,输入,输出绑定

 

  • 总结下:

学习就要总结,总结才可以提高了。哈哈!

估计还有一些朋友是头晕晕的。怎么linux的重定向这么复杂呢,又是文件打开描述符又是读,还有些,还有默认标准输入输出。

其实,总结一下,重定向应用通常就以下两点:

1、重新设置命令的默认输入,输出,指向到自己文件(文件,文件描述符,设备其实都是文件,因为linux就是基于设备也是文件,描述符也指向是文件,哈哈)

2、扩展自己新的描述符,对文件进行读写操作


相关链接

http://blog.csdn.net/flowingflying/article/details/5201199

http://www.cnblogs.com/chengmo/archive/2010/10/20/1855805.html 【讲得很好】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值