一、什么是I/O
I/O设备是计算机核心部件和外围设备进行交互的通道,因此I/O是一个统称。但这里所说的I/O与计算机的硬件设备没有太大关系,它是用来实现应用程序的I/O重定向。通常应用程序需要从外部用户获取数据,也需要将运行结果反馈给外部用户,因此程序本身要有输入输出功能,也就是和用户进行交互的功能,那么在Linux中,用户需要在命令行里为程序指定输入输出设备以便程序获取和反馈数据。
Linux的基本哲学思想是:1)一切皆文件;2)尽可能避免捕获用户接口;3)由众多目的单一应用程序组成:一个程序只做一件事,且做好;4)组合目的单一的小程序完成复杂任务;5)使用文本文件保存配置信息;6)提供机制,而非策略;
根据第二条思想,Linux应尽量避免跟用户交互,但这种潜在的需求是必然的,所以所有的程序都需要输入输出接口。为了管理方便,程序的输入输出接口都被标准化了。
标准输入:键盘,如果没有为程序指定特定的输入设备,那么默认就是键盘
标准输出:监视器(显示器)
错误输出:监视器(显示器)
Linux中一切皆文件,故通常情况下输入输出也表现为文件,而每一个打开的文件都有一个称为文件描述符(File Discriptor,简称FD)的识别标志。计算机识别字符的能力低于识别数字的能力,所以这个文件描述符通常用数字来表示:
标准输入:FD为0
标准输出:FD为1
错误输出:FD为2
注意如果某个程序运行出错了,那么就会产生错误输出,错误输出事实上和标准输出是两个文件,故它也有自己的FD,即2。但是错误输出的设备仍然是显示器,只是它和标准输出的流不是同一个,故FD不同。
每一个程序都有以上三个默认的输入输出数据流,但是如果将其定义为其他的流或其他设备,就称之为I/O重定向。
二、输出重定向
1. 输出重定向的命令:1> (这里的1可以省略,因为1是默认的)——覆盖重定向
>> ——追加重定向,可以保留原有数据
比如我们可以查看/etc目录,结果默认输入到屏幕上,但我们可以将之重定向到其他设备或文件/tmp/ls.out
# ls /etc
# ls /etc > /tmp/ls.out
# cat /tmp/ls.out
再比如使用命令 tty 可以查看当前系统打开终端的设备文件:
# tty
如果将 ls 命令的输出结果重定向到tty的设备上,就会看到当前设备上没有结果,而tty的设备有输出结果
# ls /etc > tty
由上述tty命令可以看到另一个终端的设备为 /dev/pts/0,如果将输出重定向到 /dev/null,那么将看不到任何返回结果,故将 /dev/null称为数据黑洞(bit bucket)。所以所有不想要的输出数据都可以重定向到 /dev/null,这样也不会增大系统的储存数据,/dev/null 是一个模拟设备,它吞噬一切数据而不做任何保存。
之前介绍过重定向的命令有两个:> 和 >>。>>的存在是为了解决 > 的缺陷。 使用>重定向会覆盖之前的数据,如以下例子:
# ls /var > /tmp/var.out
# cat /tmp/var.out
# cat /etc/fstab > /tmp/var.out
# cat /tmp/var.out
因此使用 > 进行重定向是非常危险的,比如误操作将 ls /var > /etc/fstab, 将会导致系统无法启动。
使用set命令和 -C选项,可以禁止覆盖,注意只对当前shell有效:
# set -C
# cat /etc/fstab > /tmp/var.out
如果被禁止覆盖后仍然坚持使用,表示强制覆盖,可以在 > 后面加上 |:
# # cat /etc/fstab >| /tmp/var.out
使用set命令和 +C选项,可以恢复覆盖,注意只对当前shell有效,如果想对所有shell有效,需要修改/etc/profile文件:
# set +C
# cat /etc/fstab > /tmp/var.out
使用 >> 命令可以进行追加重定向,故 >>是对>的补充:
# ls /var
# ls /var >> /tmp/var.out
# cat /tmp/var.out
对上述输出重定向进行一个总结:不需要保留原有数据,使用>;需要保留原有数据,使用>>;如果要防止覆盖误操作,可以使用 set -C;
2.错误输出重定向的命令:2> —— 覆盖错误重定向
2>> —— 追加错误重定向
首先来看一个例子:
# ls /ect > /tmp/etc.out
# ls /ect
上述命令无法执行是因为/ect不存在,所以 ls /ect的结果是个错误输出,错误输出和标准输出是不同的输出流,而错误输出无法使用 > 或 >> 重定向。如果要为错误输出进行重定向,可以使用: 2> 或 2>>, 因为2是错误输出的FD。
# ls /etc 2> /tmp/etc.out// 如果没有产生错误输出,将不会进行输出重定向
# cat /tmp/etc.out // 该文件是空的,因为 2>只能进行错误输出重定向
# ls /ect 2> /tmp/etc.out
# cat /tmp/etc.out
3.同时重定向标准输出和错误输出: 2> —— 覆盖错误重定向
2>> —— 追加错误重定向
COMMAND > /Path/To/StandardOut 2> /Path/To/ErrorOut
如果想将正常输出和错误输出都重定向,那么同时使用 > 和2>, 或者 >> 和 2>>
# ls /usr
# ls /usr > /tmp/usr.out 2> /tmp/usr.err
# cat /tmp/usr.out
# cat /tmp/usr.err
4.同时重定向标准输出和错误输出到一个文件: &> —— 覆盖错误重定向
&>> —— 追加错误重定向
COMMAND &> /Path/To/Somewhere
或者
COMMAND > /Path/To/Somewhere 2>&1
使用&>>可以将标准输出和错误输出都定向到一个文件中,但二者只会有一个生效:
# ls /usr &> /tmp/var2.out
# cat /tmp/var2.out
# ls /usr2 &> /tmp/var2.out
# cat /tmp/var2.out
# ls /usr2 &>> /tmp/var2.out
# cat /tmp/var2.out
# ls /usr2 >> /tmp/var2.out 2>&1
# cat /tmp/var2.out
三、输入重定向
和输出重定向相对应的是输入重定向,它使用的是 < 和 << :
COMMAND < /Path/To/Somewhere
# tr ‘a-z’‘A-Z’ /etc/fstab //此处报错,因为tr命令不接受参数,默认接受从键盘输入
# tr ‘a-z’‘A-Z’ < /etc/fstab //只有使用出入重定向才可以执行tr命令
注意,在输入重定向中,<< 不再表示追加了,而是表示创建文件,下面举例来说明它的用法:
cat > /path/to/somefile << EOF // <<后面的EOF是定义一个结束符
abc // 这里表示将 abc,hello,即 EOF前面的内容
hello // 都cat 到 /path/to/somefile 中
EOF
此命令可以用来生成文档,通常用于脚本之中,如:
# cat << EOF
abc
hello
EOF
执行此命令可以将上述abc 和 hello输出到界面上让用户看。所以在脚本中存放类似命令,就可以向用户输出大段信息。