Linux数据流重定向
- 
在之前的Linux笔记中有使用过 >、>>,比如如下指令:1 
 2
 3echo 'hello shiyanlou' > redirect 
 echo 'www.shiyanlou.com' >> redirect
 cat redirect这部分命令用于将文本字符串 “hello shiyanlou” 输出到( >)redirect文件中,此时文件并不存在,因此将自动创建redirect文件写入字符串,然后再次使用echo命令输出字符串www.shiyanlou.com追加到(>>)文件redirect中。
简单的重定向
- Linux中默认提供了三种特殊设备,用于终端的显示和输出,分别为stdin(标准输入,对应于你在终端的输入),stdout(标准输出,对应于终端的输出),stderr(标准错误输出,对应于终端的输出)。
| 文件描述符 | 设备文件 | 说明 | 
|---|---|---|
| 0 | /dev/stdin | 标准输入 | 
| 1 | /dev/stdout | 标准输出 | 
| 2 | /dev/stderr | 标准错误 | 
- 
可以这样使用文件描述符,比如默认使用终端的标准输入和标准输出作为命令的输入和输出: 1 cat 此时输入的内容也会在按下Enter时显示出来。 (按下Ctrl+C退出) 
- 
将cat的连续输出(heredoc方式)重定向到一个文件: 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11mkdir Documents 
 cat > Documents/test.c <<EOF
 int main()
 {
 printf("hello world\n");
 return 0;
 }
 EOF这一段内容的作用是将文件作为标准输出,那么之后输入的内容都会被保存在文件 /Documents/test.c中,<<EOF是文本输入的定界符,表示以下内容将作为输入直到遇到 “EOF” 为止。
- 
将一个文件作为命令的输入,标准输出作为命令的输出: 1 cat Documents/test.c 
- 
将echo命令通过管道传过来的数据作为cat命令的输入,将标准输出作为命令的输出: 1 echo 'hi' | cat 
- 
将echo命令的输出从默认的标准输出重定向到一个普通文件: 1 
 2echo 'hello shiyanlou' > redirect 
 cat redirect
标准错误重定向
- 
有时执行指令得到的输出同事包含了标准输出和标准错误,比如如下操作,使用 cat命令同时读取两个文件,其中一个存在,另一个不存在:1 cat Documents/test.c hello.c 可以看到除了正确输出了前一个文件的内容,还在末尾出现了一条错误信息. 
- 
接下来将输出重定向到一个文件: 1 cat Documents/test.c hello.c > somefile 但是依然出现了错误信息,而查看重定指向的文件,已经写入了期望包含的内容 
- 
如果希望将错误或者警告都隐藏,那就可以用到前面提到的文件描述符了。将标准错误重定向到标准输出,再将标准输出重定向到文件,注意要将重定向到文件写到前面: 1 cat Documents/test.c hello.c >somefile 2>&1 或者只用bash提供的特殊的重定向符号"&"将标准错误和标准输出同时重定向到文件: 1 cat Documents/test.c hello.c &>somefilehell 查看文件内容,可以看到错误信息也被写入到文件中了: 
使用tee命令同时重定向到多个文件
- 
如果既需要将输出重定向到文件,也需要将信息大隐刀终端,那么可以使用 tee来实现:1 echo 'hello shiyanlou' | tee hello 可以看到内容既输出在了终端,同时也被写入到了文件当中: 
永久重定向
- 
上面的操作完成的重定向只是临时的,如果希望做到永久重定向,可以使用 exec命令完成,其作用是使用指定的命令替换当前的Shell,即使用一个进程替换当前进程,或者指定新的重定向。
- 
先开启一个子Shell,然后使用exec替换当前进程的重定向,将标准输出重定向到一个文件: 1 
 2zsh 
 exec 1>somefile那么后面执行的命令的输出都将被重定向到文件中,,直到退出当前子shell,或取消exec的重定向。 1 
 2
 3ls 
 exit
 cat somefile
创建输出文件描述符
- 
在Shel 中有9个文件描述符,上面仅仅是使用了默认提供的0、1、2号文件描述符。另外我们还可以使用3-8的文件描述符,只是它们默认没有打开而已。你可以使用下面命令查看当前 Shell 进程中打开的文件描述符: 1 cd /dev/fd/;ls -Al 
- 
使用 exec命令可以创建新的文件描述并使用:1 
 2
 3
 4
 5
 6zsh 
 exec 3>somefile
 cd /dev/fd/;ls -Al;cd -
 echo "this is test" >&3
 cat somefile
 exit注意上面的第四句命令中, >与&之间不应该有空格,如果有空格则会出错
关闭文件描述符
- 
刚才设置了3号文件描述符,可以使用如下命令将其关闭: 1 
 2exec 3>&- 
 cd /dev/fd;ls -Al;cd -
完全屏蔽命令的输出
- 
在Linux中有一个被称为“黑洞”的设备文件,所有导入它的数据都会“消失“ 在类UNIX系统中, /dev/null,或称空设备,是一个特殊的设备文件,它通常被用于丢弃不需要的输出流,或作为用于输入流的空文件,这些操作通常由重定向完成。读取它则会立即得到一个EOF。
- 
我们可以利用 /dev/null屏蔽命令的输出:1 cat Documents/test.c 1>/dev/null 2>&1 上面这样的操作将使你得不到任何输出结果。 
使用 xargs 分割参数列表
- 
xargs是一条UNIX和类UNIX操作系统的常用命令,它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题。
- 
这个命令在有些时候十分有用,特别是当用来处理产生大量输出结果的命令如 find,locate 和 grep 的结果。比如这个命令用于将 /etc/passwd文件按:分割取第一个字段排序后,使用echo命令生成一个列表:1 cut -d: -f1 < /etc/passwd | sort | xargs echo 
实战训练
理解下面这段代码的作用,实际这段代码不会正常工作,请结合这一小节的知识分析这段代码没有正确工作的原因,并设法解决这个问题。
2
3
rm -iv $filename
done <<(ls)
- 
这段代码的作用是将 ls命令读取到的全部文件依次删除。
- 
但是在删除文件时会提示是否确认删除文件,而输入被 ls得到的结果重定向了,因此无法完成确认操作,上述代码无法完成执行。
- 
因此需要在删除文件时由控制台输入是否确认删除文件,而在读取删除列表时再从重定向中获得输入,修改后代码如下: - 
将文件描述符3指向标准输入: 1 exec 3<&0 
- 
删除文件,由文件描述符3提供确认操作给 rm命令,使其能够正确执行:1 rm -iv $filename <&3 
- 
遍历列表,依次删除文件: 1 
 2
 3while read filename; do 
 <delete operation>
 done <<(ls)
 
- 
- 
因此,完整代码如下: 1 
 2
 3
 4exec 3<&0 
 while read filename; do
 rm -iv $filename <&3
 done <<(ls)

















