流、管道和重定向
本节讨论初级管理(LPIC-1)考试 101 的主题 1.103.4 的内容。这个主题的权值是 5。
在本节中,学习以下主题:
- 对标准 IO 流进行重定向:标准输入、标准输出和标准错误
- 将一个命令的输出通过管道连接到另一个命令的输入
- 将输出发送到 stdout 和文件
- 将命令的输出用作另一个命令的参数
对标准 IO 进行重定向
shell 使用三种标准 I/O 流:
1. stdout 是标准输出流,显示来自命令的输出。它的文件描述符是 1。
2. stderr 是标准错误流,显示来自命令的错误输出。它的文件描述符是 2。
3. stdin 是标准输入流,向命令提供输入。它的文件描述符是 0。
输入流向程序提供输入,常常是来自终端键盘。输出流打印文本字符,常常是在终端上。终端原来是 ASCII 打字机或显示终端,但是现在常常是图形桌面上的窗口。
正如在 文本流和过滤器 一节中看到的,可以将标准输出重定向到文件或者另一个命令的标准输入,还可以将标准输入重定向为来自文件或者来自另一个命令的输出。
对输出进行重定向
对输出进行重定向有两种方法:
n>
将来自文件描述符 n 的输出重定向到文件。必须对这个文件有写权限。如果文件不存在,就创建它。如果它存在,现有内容常常会丢失而没有警告。
n>>
也将来自文件描述符 n 的输出重定向到文件。同样,必须对这个文件有写权限。如果文件不存在,就创建它。如果它存在,输出就附加到现有文件后面。
n> 或 n>> 中的 n 是指文件描述符。如果忽略,就假设是标准输出。清单 66 演示使用重定向将来自 ls 的标准输出和标准错误分别放进两个文件,这些文件是在 lpi103 目录中创建的。还演示了如何将输出附加到现有的文件中。
h24Linux联盟
清单 66. 输出重定向
[ian@echidna lpi103]$ ls x* z*
ls: z*: No such file or directory
xaa xab
[ian@echidna lpi103]$ ls x* z* >stdout.txt 2>stderr.txt
[ian@echidna lpi103]$ ls w* y*
ls: w*: No such file or directory
yaa yab
[ian@echidna lpi103]$ ls w* y* >>stdout.txt 2>>stderr.txt
[ian@echidna lpi103]$ cat stdout.txt
xaa
xab
yaa
yab
[ian@echidna lpi103]$ cat stderr.txt
ls: z*: No such file or directory
ls: w*: No such file or directory
|
使用 n> 进行输出重定向常常会覆盖现有文件。可以使用内置命令 set 的 noclobber 选项控制这种行为。如果设置了这个选项,就会在覆盖现有文件时发出警告;如果确实要覆盖,可以使用 n>|,如清单 67 所示。
h24Linux联盟
清单 67. 带 noclobber 选项的输出重定向
[ian@echidna lpi103]$ set -o noclobber
[ian@echidna lpi103]$ ls x* z* >stdout.txt 2>stderr.txt
-bash: stdout.txt: cannot overwrite existing file
[ian@echidna lpi103]$ ls x* z* >|stdout.txt 2>|stderr.txt
[ian@echidna lpi103]$ cat stdout.txt
xaa
xab
[ian@echidna lpi103]$ cat stderr.txt
ls: z*: No such file or directory
[ian@echidna lpi103]$ set +o noclobber #restore originalh24Linux联盟 noclobber setting
|
有时候希望将标准输出和标准错误重定向到同一个文件中。自动化进程或后台作业常常采用这种做法,这样就能够在以后查看输出。使用 &> 或 &>> 将标准输出和标准错误重定向到同一个位置。另一种方法是对文件描述符 n 进行重定向,然后使用 m>&n 或 m>>&n 将文件描述符 m 重定向到同一个位置。对输出进行重定向的次序很重要。例如,h24Linux联盟
command 2>&1 >output.txt h24Linux联盟
与h24Linux联盟
command >output.txt 2>&1 h24Linux联盟
不一样。清单 68 中演示了这些重定向。注意在最后一个命令中,标准输出在标准错误之后进行重定向,所以标准错误输出仍然发送到终端窗口。
h24Linux联盟
清单 68. 将两个流重定向到一个文件中
[ian@echidna lpi103]$ ls x* z* &>output.txt
[ian@echidna lpi103]$ cat output.txt
ls: z*: No such file or directory
xaa
xab
[ian@echidna lpi103]$ ls x* z* >output.txt 2>&1
[ian@echidna lpi103]$ cat output.txt
ls: z*: No such file or directory
xaa
xab
[ian@echidna lpi103]$ ls x* z* 2>&1 >output.txt
ls: z*: No such file or directory
[ian@echidna lpi103]$ cat output.txt
xaa
xab
|
有时候希望完全忽略标准输出或标准错误。为此,可以把适当的流重定向到 /dev/null 中。在清单 69 中,演示如何忽略来自 ls 命令的错误输出。
h24Linux联盟
清单 69. 使用 /dev/null 忽略输出
[ian@echidna lpi103]$ ls x* z* 2>/dev/null
xaa xab
[ian@echidna lpi103]$ cat /dev/null
|
对输入进行重定向
正如可以对 stdout 和 stderr 流进行重定向,也可以使用 < 操作符将 stdin 重定向为来自文件。在前面讨论 sort 和 uniq 时,曾经使用 tr 命令将 text1 文件中的空格替换为制表符。在这个示例中,我们使用来自 cat 命令的输出为 tr 创建标准输入。无需不断地调用 cat,现在可以使用输入重定向将空格转换为制表符,如清单 70 所示。
h24Linux联盟
清单 70. 输入重定向
[ian@echidna lpi103]$ tr ' ' '\t'<text1
1 apple
2 pear
3 banana
|
shell(包括 bash)还有 here-document 的概念,这是输入重定向的另一种形式。这使用 << 以及一个单词(比如 END),这个单词作为输入结束的标志。清单 71 演示了这种做法。
h24Linux联盟
清单 71. 用 here-document 进行输入重定向
[ian@echidna lpi103]$ sort -k2 <<END
> 1 apple
> 2 pear
> 3 banana
> END
1 apple
3 banana
2 pear
|
回忆一下在 清单 23 中是如何创建 text2 文件的。您可能会奇怪为什么不能只是输入 sort -k2,输入数据,然后按下 Ctrl-d 来结束输入。简短的答案是可以这么做,但是当时还没有学习 here-document。在 shell 脚本中常常使用 here-document(这在关于 shell、脚本、编程以及编译的主题 109 教程中讨论)。脚本没有其他方法能够判断脚本的哪些行应该作为输入对待。因为 shell 脚本大量使用制表符来进行缩进,从而提高可读性,所以 here-document 还会造成另一种麻烦。如果使用 <<- 而不是 <<,那么前面的制表符会被删除。在清单 72 中,使用与 清单 42 中一样的技术创建制表符的替代字符。然后创建一个非常小的 shell 脚本,它包含两个读取 here-document 的 cat 命令。最后,使用 .(点)命令引用(source) 脚本,这意味着在当前 shell 上下文中运行它。
h24Linux联盟
清单 72. 用 here-document 进行输入重定向
[ian@echidna lpi103]$ ht=$(echo -en "\t")
[ian@echidna lpi103]$ cat<<END>ex-here.sh
> cat <<-EOF
> apple
> EOF
> ${ht}cat <<-EOF
> ${ht}pear
> ${ht}EOF
> END
[ian@echidna lpi103]$ cat ex-here.sh
cat <<-EOF
apple
EOF
cat <<-EOF
pear
EOF
[ian@echidna lpi103]$ . ex-here.sh
apple
pear
|
管道
在 文本流和过滤器 一节中指出,文本过滤 过程就是取得文本输入流,在文本上执行某些转换,然后将它发送到输出流中。还指出,过滤常常是通过构造命令的管道 来完成的,也就是对一个命令的输出进行管道连接 或重定向,作为下一个命令的输入使用。以这种方式使用管道并不只限于文本流,尽管文本流是最常使用这些方式的地方。
将 stdout 管道连接到 stdin
我们已经看到,在两个命令之间使用 |(管道)操作符可以将第一个命令的 stdout 定向到第二个命令的 stdin。可以通过添加更多的命令和更多的管道操作符来构造长管道,如清单 73 所示。
h24Linux联盟
清单 73. 对几个命令的输出进行管道连接
command1 | command2 | command3
|
要注意的是,管道 只能 将 stdout 管道连接到 stdin。不能使用 2| 对 stderr 进行管道连接,至少用到目前为止学习的工具无法完成这种任务。如果 stderr 已经被重定向到 stdout,那么这两个流都被管道连接。在清单 74 中,使用管道对错误消息和正常输出消息进行排序,这些消息来自一个奇怪的 ls 命令,其中的通配符参数并没有按照字母表的次序排列。
h24Linux联盟
清单 74. 对两个输出流进行管道连接
[ian@echidna lpi103]$ ls y* x* z* u* q* 2>&1 |sort
ls: q*: No such file or directory
ls: u*: No such file or directory
ls: z*: No such file or directory
xaa
xab
yaa
yab
|
管道中的任何命令都可以有选项或参数。许多命令使用连字符(-)替代文件名参数,这表示输入应该来自 stdin 而不是文件。请查看命令的手册页。将功能有限的多个命令连接成长的管道是在 Linux 和 UNIX 上完成任务的常用方式。
在 Linux 和 UNIX 系统上管道的一个优点是,与某些其他流行的操作系统不同,管道不涉及中间文件。第一个命令的 stdout 并不是 写到文件中,然后再由第二个命令读取。如果您的 tar 版本碰巧不支持使用 bzip2 对压缩的文件进行解压,那么没关系。在主题 102 的教程中可以看到,可以使用管道 h24Linux联盟
h24Linux联盟
bunzip2 -c drgeo-1.1.0.tar.bz2 | tar -xvf - h24Linux联盟
Linux联盟收集整理 ,转贴请标明原始链接,如有任何疑问欢迎来本站Linux论坛讨论