1.介绍
IO重定向用于捕捉一个文件,命令,程序,脚本或者代码块的输出,然后把捕捉到的输出作为输入发送给另外一个文件,命令,程序或脚本。
终端程序一般从单一源以流的形式聚集输入和显示输出,script执行时(进程), 系统会默认开启3个标准文件,stdin, stdout,stderr . script默认会由stdin读取数据,默认指键盘,由stdout输出执行结果,默认指屏幕; 若有错误发生,则由stderr显示信息,默认也指向屏幕。系统开启这3个文件时,以文件代码(分别为0,1,2)作为连接,这三个文件被称为标准I/O.Linux Shell 环境中支持标准输入输出重定向,用符号<和>来表示,故可以用来指定需要重定向的标准输入或输出,比如 2>a.txt 表示将错误信息输出到文件a.txt中。
同时,还可以在这三个标准输入输出之间实现重定向,比如将错误信息重定向到标准输出,可以用 2>&1来实现。常用的用法之一是将输出重定向至 /dev/null 来禁止输出。
2. file descriptor FD
进程必须先打开一个文件,才能读取或写入文件,Linux进程通过给每个当前被打开的文件赋整数值(从0开始)来追踪文件,这个整数被称为文件描述符,之后对此文件的操作都使用FD来完成。Linux通过/proc 文件系统来检查当前运行进程打开的文件和文件描述符/proc/pid/fd,pid 即对应进程ID,fd 文件夹下以整数文件描述符命名的符号链接,链接到打开文件本身。
每一个I/O管道被用一个整数命名,文件描述符可以与常规文件、设备节点、网络套接字连接(即在虚拟文件系统/proc中,以数字命令的链接文件,链接到指定文件)。
其中0,1,2三个特殊的FD,就是STDIN,STDOUT,STDERR,分别指向相应的设备文件
标准输入STDIN:程序读取的源
标准输出STDOUT:程序写入的目的地
标准错误STDERR:程序将出错状况报告给一个叫标准错误stderr 的目的地
| FD | 默认输出位置 | 重定向操作符 |
STDIN | 0 | keyboard input | (0)< (0)<< |
STDOUT | 1 | mointor | (1)> (1)>> |
STDERR | 2 | monitor | 2> 2>> |
3. Pipeline and redirection
Pipe将多个命令连接在一起,是Linux的一种基本的进程间通信技术。它的设计符合Unix哲学:复杂的系统应该由简单的、专门的、互操作简单的组件构成,故许多标准Linux程序被设计为过滤器。
管道:把一个进程的标准输出流与另一个进程的标准输入流连接起来,管道符|用于连接一个命令的标准输出与另一条命令的标准输入
pipe 命令:pipe 后面接的第一个数据必定是指令,且这个指令必须能够接受stdin 数据并处理, pipe 命令仅处理stdout , 而忽略stderr ,并将处理结果传递给标准输出,如grep , head, tail, cut, sort, expand,sed,awk,fmt,tac,tr,grep,nl,pr , sed ,awk
过滤器(filters):用来接收标准输入,经过过滤器命令的转化,再写到标准输出。如cat test | grep ade| tac 中|grep| 即为过滤器
4. 重定向
即不使用系统默认的标准输入输出,而是重新指定,即输入重定向,输出重定向,错误输出重定向,
双重输出重定向(一次单独地送到不同的地方)。IO重定向其实就是让已创建的FD指向其它的文件(修改其链接的文件)。输入输出数据流的位置用FD标识。
IO重定向的原理就是通过exec 来操作FD(修改FD所指向的文件),来实现将输入和输出设定为指定的文件(或设备)。关于重定向需要注意:
- I/O重定向与 FD有关,shell的FD通常为10个,即 0~9;
- 在IO重定向中,stdout 与 stderr 的管道会先准备好,才会从 stdin 读取文档;
- 重定向操作发生的时间是在命令执行开始之前
- 对同一个文件描述符多次进行重定向操作,后发生的会覆盖先发生的操作,重定向的最终结果是最后一次重定向命令
- bash(ksh)执行命令的过程:分析命令-变量求值-命令替代(``和$( ))-重定向-通配符展开-确定路径-执行命令;
- ( ) 将 command group 置于子shell 去执行,它会继承父shell的Standard input, output, and error 和 any other open file descriptors, 这就是为什么子shell中执行的命令输出也一样会打印到屏幕。
基本IO重定向
cmd > file 把 stdout 重定向到 file 文件中;
cmd 1> file 同上
cmd >> file 把 stdout 重定向到 file 文件中(追加);
cmd 2> file 把 stderr 重定向到 file 文件中;
cmd 2>> file 把 stderr 重定向到 file 文件中(追加);
cmd > file 2>&1 把 stderr和 stdout 一起重定向到 file 文件中;
cmd &>file 上一例的简写形式
cmd >> file 2>&1 把 stderr 和 stderr 一起重定向到 file 文件中(追加);
cmd >/dev/null 2>/dev/null 不记录标准输出或标准错误输出
cmd &>/dev/null 同上
cmd < file cmd 命令以 file 文件作为 stdin;
cmd < file >file2 cmd 命令以 file 文件作为 stdin,以 file2 文件作为 stdout;
cmd << delimiter Here document,从 stdin 中读入,直至遇到 delimiter 分界符。
示例说明
find / -name 2>/dev/null
date>file1 标准输出无内容,file1中有内容。(先执行重定向)
(date)>file1 标准输出无内容,file1中有内容。(先将子shell 标准输出重定向至file1)
(date >file1) >file2 file1中有内容,file2中无内容。(将子shell 标准输出重定向至file2;子shell中,date标准输出重定向至file1,子shell标准输出没有内容,file1中有内容)
date >file1 >file2 file1中无内容,file2中有内容。(将date 标准输出重定向至file1,然后再将date标准输出重定向至file2,都是针对同一个文件描述符,会覆盖.
> test.txt 新建空白文件,或者清空文件(危险命令), 多用于清空日志
> /dev/sda 会导致整个块设备的数据丢失
5. IO重定向符号汇总
cmd n>file | 将FD为n的输出写入file |
cmd >file | 标准输出写入file中 FD为1,即将标准输出重定向到file > 为1>的简写形式 |
cmd n<file | 将file读入到FD n中 |
cmd <file | 将file 读入标准输入中 FD为0, 即将标准输入重定向到file < 为0<的简写形式 |
cmd n>>file | 将FD为n的输入追加写入到file |
cmd >>file | 追加输出至file中,FD为1 |
cmd >|file | 忽略shell的noclobber选项,强制覆盖file |
cmd n>|file | 忽略noclobber选项(shell选项),强制将FD为n的输出写入file |
cmd n>>|file | 忽略noclobber选项 |
<<delimiter | |
cmd1 | cmd2 | 管道符|(特殊IO重定向), 将cmd1的标准输出作为cmd2的标准输入 |
5.脚本中临时重定向每一行
此方法可以为生成错误消息提供方便
cat retest.sh
#!/bin/bash
echo "this is an error" >&2 #重定向至指定FD,此处重定向至标准错误输出
echo "this is normal output"
echo "redirect this line to standard output" >&1
[ade@h test]$ ./test.sh >test1 2>test2
[ade@h test]$ cat test1
this is normal output
redirect this line to standard output
[ade@h test]$ cat test2
this is an error
7. 脚本中代码块重定向
代码重定向是指在代码块内将标准输入或标准输出重定向到文件,而代码块之外而保持默认状态(即重定向只对代码块有效,而不是整个脚本),它可以让代码块方便的处理一个文件,它也是脚本中的临时重定向,特别之处是它针对的是shell脚本中相应的结构代码。
while,until,for,if/then, 函数等代码块都可以使用重定向,<输入重定向,>输出重定向。
cat rewhile.sh
#!/bin/bash
ls /etc > loggg
while [ "$filename" != "rc.d" ]
do
read filename
let "count +=1"
done < loggg
echo "$count times read"
#测试循环体外的标准输入是否被重定向
echo -n " ------pls input data:---------"
read test
echo $test
cat reif.sh
if [ -z "$1" ]
then
echo "positional parameter is null"
fi > loggg
echo "-----------Normal stdout--------"
其它结构的重定向
for
do
......
done < loggg
if [condition]
then
...
else
...
fi < loggg
until [condition]
do
...
done < loggg
8. 脚本中永久重定向所有命令
当希望将脚本中的很多输出都重定向时,可以使用exec 通知shell在脚本执行时重定向特定的文件描述符。实例上是使用exec 来完成FD的相关操作。
cat test1.sh
#!/bin/bash
exec 1>testout
echo "line one"
echo "line two"
echo "line three"
cat test.sh
#!/bin/bash
exec 2>testerr
echo "this is the start of the script"
echo "the following command will redirect all ouptput to testout"
exec 1> testout #or exec > testout
echo " put this line into testout"
echo "put this line into testerr" >&2
[ade@h test]$ ./test.sh
this is the start of the script
the following command will redirect all ouptput to testout
[ade@h test]$ cat testout
put this line into testout
[ade@h test]$ cat testerr
put this line into tester
refer
man bash here documents 部分
awk, fold, grep, head, nnkf, pr, sed, sort, tail, tee, tr, uniq, wc
lsof : 列出所有开放的文件描述符