开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
@TOC
前言
这章 我们介绍可能是命令行最酷的特性——I/O 重定向
。
“I/O” 代表输入/输出,通过这个工具,你可以重定向命令的输入输出。
命令的输入来自文件,而输出也存到文件。也可以把多个命令连接起来组成一个强大的命令管道。
本章涉及以下命令:
- cat -连接文件
- sort -排序文本行
- uniq -报道或省略重复行
- grep -打印匹配行
- wc -打印文件中换行符,字,和字节个数
- head -输出文件第一部分
- tail - 输出文件最后一部分
一、重定向
1.1 标准输入,输出,和错误
许多程序都会产生某种输出。
这种输出
,经常由两种类型组成:
第一,程序运行结果
;这是说,程序要完成的功能。第二,我们得到状态和错误信息
,这些告诉我们程序进展。
例如:ls,会看到它的运行结果
和错误信息
显示在屏幕上。
实际上程序把他们的运行结果输送到一个叫做标准输出的特殊文件(经常用 stdout 表示)
,而它们的状态信息则送到另一个叫做标准错误的文件(stderr)
。
默认情况下,标准输出和标准错误都连接到屏幕,而不是保存到磁盘文件。
许多程序从一个叫做标准输入(stdin)
的设备得到输入。
默认情况下,标准输入连接到键盘。
I/O 重定向允许我们可以更改输出走向和输入来向。
一般地,输出送到屏幕,输入来自键盘,但是通过 I/O 重定向,我们可以改变输入输出方向
。
1.2 重定向标准输出
I/O 重定向允许我们来重定义标准输出送到哪里:
- 输出设备,例如显示屏
- 文件
标准输出到文件
使用 “>
” 重定向符,其后跟着文件名
ls -l /usr/bin > ls-output.txt
我们创建了一个长长的目录/usr/bin 列表,并且输送程序运行结果到文件 ls-output.txt 中。 检查一下命令结果:
[me@linuxbox ~]$ ls -l ls-output.txt
-rw-rw-r-- 1 me me 167878 2008-02-01 15:07 ls-output.txt
文件存在且检查文件内容会发现正是ls的内容
标准错误输出到文件
这次我们输入一个不存在目录
[me@linuxbox ~]$ ls -l /bin/usr > ls-output.txt
ls: cannot access /bin/usr: No such file or directory
我们收到一个错误信息。这很有意义,因为我们指定了一个不存在的目录/bin/usr, 但是为什么这条错误信息显示在屏幕上而不是被重定向到文件 ls-output.txt?
答:因为我们只是重定向了标准输出,而没有重定向标准错误,所以错误信息被送到屏幕。
同样地,我们检查一下文件
me@linuxbox ~]$ ls -l ls-output.txt
-rw-rw-r-- 1 me me 0 2008-02-01 15:08 ls-output.txt
文件大小为0,当我们使用 “>” 重定向符来重定向输出结果时,目标文件总是从开头被重写。因为我们 ls 命令没有产生运行结果,只有错误信息,重定向操作开始重写文件,然后由于错误而停止,导致文件内容删除。
事实上,如果我们需要删除一个文件内容(或者创建一个新的空文件),可以使用这样的技巧:
[me@linuxbox ~]$ > ls-output.txt
另外,怎样才能把重定向结果追加到文件内容后面,而不是从开头重写文件?
为了这个目的,我们使用 “>>
” 重定向符,像这样:
[me@linuxbox ~]$ ls -l /usr/bin >> ls-output.txt
使用 “>>” 操作符,将导致输出结果添加到文件内容之后。如果文件不存在,文件会被创建,就如同使用了’>’ 操作符。
1.3 重定向标准错误
重定向标准错误缺乏专用的重定向操作符。重定向标准错误,我们必须参考它的文件描述符。一个程序可以在几个编号的文件流中的任一个上产生输出。
然而我们必须把这些文件流的前三个看作标准输入
,输出
和错误
,shell内部它们的文件描述符分别为 0,1 和 2。
因为标准错误和文件描述符2一样
[me@linuxbox ~]$ ls -l /bin/usr 2> ls-error.txt
形如:command
+ 2>
+ 文件名
1.4 重定向标准输出和错误到同一个文件
可能有这种情况,我们希望捕捉一个命令的所有输出到一个文件。为了完成这个,我们必须同时重定向标准输出和标准错误。
有两种方法来完成任务:
- 第一个,传统的方法,在旧版本shell 中也有效:
[me@linuxbox ~]$ ls -l /bin/usr > ls-output.txt 2>&1
使用这种方法,我们完成两个重定向。
- 首先重定向标准输出到文件 ls-output.txt
- 然后重定向文件描述符 2(标准错误)到文件描述符 1(标准输出)使用表示法 2>&1。
注意重定向的顺序安排非常重要。标准错误的重定向必须总是出现在标准输出重定向之后,要不然它不起作用。
上面的例子
>ls-output.txt 2>&1
标准输出1
重定向到ls-output.txt
标准错误2
重定向到1,而此时1指向 ls-output.txt 所以2也指向 ls-output.txt
- bash 版本提供了第二种方法,更精简合理的方法来执行这种联合的重定向:
[me@linuxbox ~]$ ls -l /bin/usr &> ls-output.txt
单单一个表示法 &>
来重定向标准输出和错误
都到文件 ls-output.txt。
简单记,就是&有与的含义 所以1,2都重定向到ls-output.txt
1.5 处理不需要的输出
当我们不想要一个命令的输出结果,只想把它们扔掉。这种情况尤其适用于错误和状态信息。系统为我们提供了解决问题的方法,通过重定向输出结果到一个特殊的叫做 “/dev/null
” 的文件。这个文件是系统设备,叫做位存储桶,它可以接受输入,并且对输入不做任何处理。
为了隐瞒命令错误信息,我们这样做:
[me@linuxbox ~]$ ls -l /bin/usr 2> /dev/null
小贴士: Unix 文化中的/dev/null 位存储桶是个古老的 Unix 概念,由于它的普遍性,它的身影出现在 Unix 文化的许多部分。当有人说他/她正在发送你的评论到/dev/null,现在你应该知道那是什么意思了。
1.6 重定向标准输入
重定向标准输入的命令有:
- cat -连接文件
1.7 cat - 连接文件
cat 命令读取一个或多个文件,然后复制它们到标准输出,就像这样:
cat [file]
cat命令有几种用法:
1.显示文件简短信息
2.可以用来把文件连接在一起
cat movie.mpeg.0* > movie.mpeg
3.显示输入的内容
[me@linuxbox ~]$ cat
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
这是你输入的内容
下一步,输入 Ctrl-d(按住 Ctrl 键同时按下 “d”)
,来告诉 cat,在标准输入中,它已经到达文件末尾(EOF):
由于文件名参数的缺席,cat 复制标准输入到标准输出,所以我们看到文本行重复出现。
4.重定向输入的内容到某个文件
我们想创建一个叫做 “lazy dog.txt” 的文件,这个文件包含例子中的文本。我们这样做:
[me@linuxbox ~]$ cat > lazy_dog.txt
The quick brown fox jumped over the lazy dog
输入命令,其后输入要放入文件中的文本。记住,最后输入 Ctrl-d。通过使用这个命令,我们实现了世界上最低能的文字处理器!
5.重定向标准输入由键盘改为由文件
[me@linuxbox ~]$ cat < lazy_dog.txt
The quick brown fox jumped over the lazy dog
(lazy_dog.txt文件内容是The quick brown fox jumped over the lazy dog
)
cat显示出lazy_dog.txt的内容。
使用“<
”重定向操作符,我们把标准输入源
从键盘改到文件 lazy dog.tx
。
我们看到结果和传递单个文件名作为参数的执行结果一样。 把这和传递一个文件名参数作比较,尤其没有意义,但它是用来说明把一个文件作为标准输入源。
看一下运行结果,我们使用 cat 来复制文件内容到标准输出.
[me@linuxbox ~]$ cat lazy_dog.txt
The quick brown fox jumped over the lazy dog.
1.8 管道线
命令可以从标准输入读取数据,然后再把数据输送到标准输出,命令的这种能力被一个shell 特性所利用,这个特性叫做管道线
。
使用管道操作符 “|
”(竖杠),一个命令的标准输出
可以管道到另一个命令的标准输入
:
command1 | command2
我们用 less 来一页一页地显示任何命令的输出,命令把它的运行结果输送到标准输出
[me@linuxbox ~]$ ls -l /usr/bin | less
使用这项技术,我们可以方便地检测会产生标准输出的任一命令的运行结果。
1.9 过滤器
管道线经常用来对数据完成复杂的操作。有可能会把几个命令放在一起组成一个管道线。通常,以这种方式使用的命令被称为过滤器
。
过滤器接受输入,以某种方式改变它,然后输出它。
第一个我们想试验的过滤器是 sort。想象一下,我们想把目录/bin 和/usr/bin 中的可执行程序都联合在一起,再把它们排序,然后浏览执行结果
[me@linuxbox ~]$ ls /bin /usr/bin | sort | less
因为我们指定了两个目录(/bin 和/usr/bin),ls 命令的输出结果由有序列表组成,各自针对一个目录。通过在管道线中包含 sort,我们改变输出数据,从而产生一个有序列表。
1.10 uniq - 报道或忽略重复行
uniq 命令经常和 sort 命令结合在一起使用。 uniq 从标准输入或单个文件名参数接受数据有序列表(详情查看 uniq 手册页),默认情况下,从数据列表中删除任何重复行。
所以,为了确信我们的列表中不包含重复句子(这是说,出现在目录/bin 和/usr/bin 中重名的程序),我们添加 uniq 到我们的管道线中:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | less
在这个例子中,我们使用 uniq 从 sort 命令的输出结果中,来删除任何重复行。如果我们想看到重复的数据列表,让 uniq 命令带上 “-d” 选项,就像这样:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq -d | less
1.11 wc -打印行,字和字节数
wc(字计数)命令
是用来显示文件所包含的行,字和字节数。
[me@linuxbox ~]$ wc ls-output.txt
7902 64566 503634 ls-output.txt
在这个例子中,wc 打印出来三个数字:包含在文件 ls-output.txt 中的行数,单词数和字节数,正如我们先前的命令,如果 wc 不带命令行参数,它接受标准输入。“-l” 选项限制命令输出只能报道行数。添加 wc 到管道线来统计数据,是个很便利的方法。
查看我们的有序列表中程序个数,我们可以这样做:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | wc -l
2728
1.12 grep -打印匹配行
grep
命令 用来找到文件中的匹配文本。
grep pattern [file...]
当 grep 遇到一个文件中的匹配 “模式”,它会打印出包含这个类型的行。grep 能够匹配的模式可以很复杂,但是现在我们把注意力集中在简单文本匹配上面。
grep更高级的使用方法是正则表达式
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | grep zip
bunzip2
bzip2
gunzip
...
grep 有-对方便的选项:“-i” 导致 grep 忽略大小写当执行搜索时(通常,搜索是大小写敏感的),“-v” 选项会告诉 grep 只打印不匹配的行。
1.13 head / tail -打印文件开头部分/结尾部分
有时候你不需要一个命令的所有输出。可能你只想要前几行或者后几行的输出内容。
head命令
打印文件的前十行,而tail 命令
打印文件的后十行。
默认情况下,两个命令都打印十行文本,但是可以通过 “-n” 选项来调整命令打印的行数。
[me@linuxbox ~]$ head -n 5 ls-output.txt
total 343496
...
[me@linuxbox ~]$ tail -n 5 ls-output.txt
...
它们也能用在管道线中:
[me@linuxbox ~]$ ls /usr/bin | tail -n 5
znew
...
tail 有一个选项允许你实时的浏览文件。当观察日志文件的进展时,这很有用,因为它们同时在被写入。在以下的例子里,我们要查看目录/var/log 里面的信息文件。在一些 Linux 发行版中,要求有超级用户权限才能阅读这些文件,因为文件/var/log/messages 可能包含安全信息。
[me@linuxbox ~]$ tail -f /var/log/messages
Feb 8 13:40:05 twin4 dhclient: DHCPACK from 192.168.1.1
....
使用 “-f” 选项,tail 命令继续监测这个文件,当新的内容添加到文件后,它们会立即出现在屏幕上。这会一直继续下去直到你输入 Ctrl-c。
1.14 tee - 从 Stdin 读取数据,并同时输出到 Stdout 和文件、
为了和我们的管道隐喻保持一致,Linux 提供了一个叫做 tee 的命令,这个命令制造了一个 “tee”,安装到我们的管道上。tee 程序从标准输入读入数据,并且同时复制数据到标准输出(允许数据继续随着管道线流动)和一个或多个文件。当在某个中间处理阶段来捕捉一个管道线的内容时,这很有帮助。这里,我们重复执行一个先前的例子,这次包含 tee 命令,在 grep过滤管道线的内容之前,来捕捉整个目录列表到文件 ls.txt:
[me@linuxbox ~]$ ls /usr/bin | tee ls.txt | grep zip
bunzip2
bzip2
....
总结
在这一章中,我们主要学会了这些:
- 重定向标准输出(>,>>)
- 重定向错误输出(2>&1,&>)
- 不处理输出(2> /dev/nul)
- 重定向标准输入(<)
- 管道线(|)