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
实战训练
理解下面这段代码的作用,实际这段代码不会正常工作,请结合这一小节的知识分析这段代码没有正确工作的原因,并设法解决这个问题。
1
2
3 while read filename; do
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)