17.2 I/O重定向

17.2.1 I/O重定向符号和用法

I/O重定向是重定向中的一个重要部分,在Shell编程中会有很多机会用到这个功能。简单来说,I/O重定向可以将任何文件、命令、脚本、程序或脚本的输出重定向到另外一个文件、命令、程序或脚本。

I/O重定向常见符号和功能描述如表17-1所示。

表17-1 常见的I/O重定向符号

17.2 I/O重定向 - 图1

读者初次看到表17-1一定会感觉不知所云,所以下面将逐一介绍上述符号的具体使用方法,建议读者跟随所讲的内容动手实践,以加深理解。

1.标准输出覆盖重定向:>

使用标准输出覆盖重定向符号可以将原本输出到显示器上的内容重定向到一个文件中,比如使用ls-l可以列出指定目录中文件的详细信息,但是如果想把结果保存到文件中以便日后查看,则可以使用标准输出覆盖重定向符。示例如下:


  1. #
  2. 列出/usr
  3. 目录中的文件信息,默认所产生的输出会显示在屏幕上
  4. [root@localhost ]# ls -l usr
  5. total 176
  6. drwxr-xr-x 2 root root 40960 Apr 11 11:19 bin
  7. drwxr-xr-x 2 root root 4096 Oct 1 2009 etc
  8. drwxr-xr-x 2 root root 4096 Oct 1 2009 games
  9. drwxr-xr-x 50 root root 4096 Apr 11 10:21 include
  10. drwxr-xr-x 6 root root 4096 Feb 23 2012 kerberos
  11. drwxr-xr-x 99 root root 36864 Apr 11 11:19 lib
  12. drwxr-xr-x 11 root root 4096 Apr 11 11:19 libexec
  13. drwxr-xr-x 12 root root 4096 Apr 11 10:38 local
  14. drwxr-xr-x 2 root root 12288 Apr 11 11:19 sbin
  15. drwxr-xr-x 183 root root 4096 Apr 11 10:21 share
  16. drwxr-xr-x 4 root root 4096 Feb 26 21:13 src
  17. lrwxrwxrwx 1 root root 10 Feb 26 21:13 tmp -> ..vartmp
  18. drwxr-xr-x 3 root root 4096 Feb 26 21:15 X11R6
  19. [root@localhost ]# ls -l usr > ls_usr.txt #
  20. 回车
  21. [root@localhost ]# #
  22. 注意到回车后并没有任何输出,因为输出被重定向到文件中
  23. [root@localhost ]# cat ls_usr.txt #
  24. 此文件内容和之前的输出一致
  25. total 176
  26. drwxr-xr-x 2 root root 40960 Apr 11 11:19 bin
  27. drwxr-xr-x 2 root root 4096 Oct 1 2009 etc
  28. drwxr-xr-x 2 root root 4096 Oct 1 2009 games
  29. drwxr-xr-x 50 root root 4096 Apr 11 10:21 include
  30. drwxr-xr-x 6 root root 4096 Feb 23 2012 kerberos
  31. drwxr-xr-x 99 root root 36864 Apr 11 11:19 lib
  32. drwxr-xr-x 11 root root 4096 Apr 11 11:19 libexec
  33. drwxr-xr-x 12 root root 4096 Apr 11 10:38 local
  34. drwxr-xr-x 2 root root 12288 Apr 11 11:19 sbin
  35. drwxr-xr-x 183 root root 4096 Apr 11 10:21 share
  36. drwxr-xr-x 4 root root 4096 Feb 26 21:13 src
  37. lrwxrwxrwx 1 root root 10 Feb 26 21:13 tmp -> ..vartmp
  38. drwxr-xr-x 3 root root 4096 Feb 26 21:15 X11R6

请注意,如果指定的重定向文件不存在,则命令会先创建这个文件,如果文件存在且内容不为空,则原文件内容将被全部清空。所以有时候需要先判断该文件是否存在,以避免不小心破坏了原有文件内容。

下面尝试ls一个不存在的文件,看看会发生什么。


  1. [root@localhost ~]# ls -l usrnoExist > ls_noExist.txt
  2. ls: usrnoExist: No such file or directory

这里ls命令发现指定的文件不存在后给出了错误输出。这是为什么呢?

标准输出覆盖重定向其实是默认将文件标识符为1的内容重定向到指定文件中,所以如下两种写法是等价的,或者说,第一种写法是第二种写法的“省略写法”。


  1. #
  2. 标准输出覆盖重定向符默认只将文件标识符为1
  3. 的内容重定向到指定文件
  4. [root@localhost ~]# ls -l usr > ls_usr.txt
  5. #
  6. 以上写法等价于
  7. [root@localhost ~]# ls -l usr 1> ls_usr.txt

如果命令由于各种原因出错时所产生的错误输出,其文件标识符为2,而标准错误的输出默认也是显示器。所以我们可以通过指定将文件标识符为2的内容重定向到指定文件,这样错误输出就不会出现在显示器上了。如下所示:


  1. [root@localhost ~]# ls -l usrnoExist 2> ls_noExist_err.txt#
  2. 错误输出被重定向到文件中
  3. [root@localhost ~]# cat ls_noExist_err.txt
  4. ls: usrnoExist: No such file or directory

如果某命令的输出既有标准输出,又有标准错误输出,则可以分别指定不同标识符的内容输出到不同的文件中。


  1. [root@localhost ~]# COMMAND 1> stdout.txt 2>stderr.txt

2.标准输出追加重定向:>>

该符号用法和>完全一致,不同的只是如果指定的重定向文件存在且内容不为空,重定向并不会清空原文件内容,而是将命令的输出新增到原文件的尾部。在下面的例子中,先后将/usr和/tmp目录中列出的内容追加重定向到append.txt文件。


  1. [root@localhost ]# ls -l usr >> append.txt
  2. [root@localhost ]# ls -l tmp >> append.txt
  3. [root@localhost ~]# cat append.txt
  4. total 176
  5. drwxr-xr-x 2 root root 40960 Apr 11 11:19 bin
  6. drwxr-xr-x 2 root root 4096 Oct 1 2009 etc
  7. drwxr-xr-x 2 root root 4096 Oct 1 2009 games
  8. drwxr-xr-x 50 root root 4096 Apr 11 10:21 include
  9. drwxr-xr-x 6 root root 4096 Feb 23 2012 kerberos
  10. drwxr-xr-x 99 root root 36864 Apr 11 11:19 lib
  11. drwxr-xr-x 11 root root 4096 Apr 11 11:19 libexec
  12. drwxr-xr-x 12 root root 4096 Apr 11 10:38 local
  13. drwxr-xr-x 2 root root 12288 Apr 11 11:19 sbin
  14. drwxr-xr-x 183 root root 4096 Apr 11 10:21 share
  15. drwxr-xr-x 4 root root 4096 Feb 26 21:13 src
  16. lrwxrwxrwx 1 root root 10 Feb 26 21:13 tmp -> ..vartmp
  17. drwxr-xr-x 3 root root 4096 Feb 26 21:15 X11R6
  18. total 0
  19. srwxr-xr-x 1 root root 0 Mar 1 11:27 gedit.root.903135227
  20. srwxr-xr-x 1 root root 0 Mar 28 00:18 mapping-root

3.标识输出重定向:>&

标识输出重定向的作用是将一个标识的输出重定向到另一个标识的输入。比如想要将标准输出和标准错误同时定向到同一个文件中,可使用如下命令:


  1. [root@localhost ~]# COMMAND > stdout_stderr.txt 2>&1

上面演示的命令从左到右可以读为:执行COMMAND命令,将标准输出的内容重定向到stdout_stderr.txt中,如果有标准错误输出也同时重定向到该文件中。

为演示执行某个命令后既有标准输出又有错误输出的情景,可以使用普通用户执行以下命令,从输出内容可以看到,除了标准输出外还有很多由于文件权限问题而出现的错误输出。


  1. [user1@localhost ~]$ find / -type f -name *.txt
  2. find: varlog/httpd: Permission denied
  3. find: varlog/ppp: Permission denied
  4. find: varlog/audit: Permission denied
  5. find: varlog/samba: Permission denied
  6. find: proc11771/task/11771/fd: Permission denied
  7. find: proc11771/fd: Permission denied
  8. find: proc11951/task/11951/fd: Permission denied
  9. find: proc11951/fd: Permission denied
  10. find: proc11953/task/11953/fd: Permission denied
  11. find: proc11953/fd: Permission denied
  12. find: proc11985/task/11985/fd: Permission denied
  13. find: proc11985/fd: Permission denied
  14. find: proc12021/task/12021/fd: Permission denied
  15. ......(
  16. 略去内容)......
  17. usrlib/python2.4/email/test/data/msg_16.txt
  18. usrlib/xulrunner-1.9/README.txt
  19. find: usrlib/audit: Permission denied
  20. usrlib/firefox-3.0.18/README.txt

现试图将上述所有输出重定向到某个文件中,使用以下命令只能将标准输出覆盖重定向到find_res01.txt文件,而大量的错误输出依然会出现在显示器上。


  1. [user1@localhost ~]$ find / -type f -name *.txt > find_res01.txt
  2. find: varlog/httpd: Permission denied
  3. find: varlog/ppp: Permission denied
  4. find: varlog/audit: Permission denied
  5. find: varlog/samba: Permission denied
  6. find: varempty/sshd: Permission denied
  7. find: varrun/cups/certs: Permission denied

下面使用标识输出重定向,将标准错误输出同时定向到find_res01.txt文件。


  1. [user1@localhost ]$ find / -type f -name *.txt > find_res01.txt 2>&1
  2. [user1@localhost ]$ #
  3. 屏幕上看不到任何输出

很多时候大家并不会在意错误输出,特别是一些系统后台任务可能在每天凌晨运行,这时出现的错误输出可能并不是系统管理员所关心的,所以也没有必要将错误输出保存到任何文件中。这时可以利用系统中的一个特殊设备devnull,将所有错误输出重定向到该设备中——系统会将任何输入到该设备的内容全部删除(就像一个宇宙黑洞)。


  1. [root@localhost ~]# COMMAND > stdout.txt 2> devnull

4.标准输入重定向:<

标准输入重定向可以将原本应由从标准输入设备中读取的内容转由文件内容输入,也就是将文件内容写入标准输入中。

下面的例子中首先运行cat命令,系统将等待键盘输入。如果此时输入Hello并回车,cat命令会读取并立即输出Hello,然后命令将继续等待输入,直到使用Ctrl+D组合键终止输入。


  1. [root@localhost ~]# cat
  2. Hello #
  3. 从键盘输入Hello
  4. Hello #cat
  5. 命令读取并输出Hello
  6. World #
  7. 从键盘输入World
  8. World #cat
  9. 命令读取并输出World
  10. [Ctrl+D]
  11. 终止输入
  12. [root@localhost ~]#

在下面的例一中,先将要打印的内容提前写到某个文件中,比如HelloWorld01.txt,然后使用标准输入重定向将内容重定向给cat命令。从命令输出结果可以看出,文件内容被标准输入重定向给了cat命令,然后该命令忠实地履行了打印任务。


  1. #
  2. 例一:给cat
  3. 的标准输入重定向
  4. [root@localhost ~]# cat HelloWorld01.txt
  5. Hello
  6. World
  7. [root@localhost ~]# cat < HelloWorld01.txt
  8. Hello
  9. World

下面是使用sort排序的例子,运行sort命令后系统将等待键盘输入,依次输入3个单词并以回车符隔开,输入结束后使用Ctrl+D组合键终止输入。此时sort命令会打印出排序后的单词列表。


  1. [root@localhost ~]# sort
  2. banana
  3. apple
  4. carrot
  5. [Ctrl+D]
  6. 终止输入
  7. apple
  8. banana
  9. carrot
  10. [root@localhost ~]#

如果将需要排序的单词预先写到fruit01.txt文件中,然后使用标准输入重定向给sort命令,效果和之前一致,如例二所示:


  1. #
  2. 例二:给sort
  3. 的标准输入重定向
  4. [root@localhost ~]# cat fruit01.txt
  5. banana
  6. apple
  7. carrot
  8. [root@localhost ~]# sort < fruit01.txt
  9. apple
  10. banana
  11. carrot

5.管道:|

管道也是一种重要的I/O重定向方法,在第5章中我们已经介绍过管道的概念和基本用法。简单地说管道就是将一个命令的输出作为另一个命令的输入,借此方式可通过多个简单命令的共同协作来完成较为复杂的工作。读者可以行复习第5章来加强对管道的理解。