每日一Shell(3) 文件描述符及重定向

什么是文件描述符

文件描述符是与某个打开的文件或数据流相关的整数。文件描述符 0,1,2 是系统预留的:

  • 0 – stdin
  • 1 – stdout
  • 2 – stderr

1. 将输出流重定向到一个文件中

echo "Hello world" > hello.txt

2. 追加而不是覆盖文件

第一个例子会把原来的文件清空然后写入,使用 >> 就可以从后面追加而不是把原来文件的内容删掉:

echo "Hello world" >> hello.txt

3. 错误输出流

错误输出流默认会显示在屏幕中:

$ ls + > /dev/null

由于 ls + 会报错,因此即使 stdout 被重定向了,屏幕还是会将从 stderr 的错误信息打印出来。

如果需要重定向输出流,可以在 > 或者 > 前面加上文件描述符的编号 2

$ ls + 2> err.txt

或者追加:

$ ls + 2>> err.txt

4. 分别重定向 stderr 和 stdout

cmd 2> stderr.txt 1> stdout.txt

5. 将 stderr 和 stdout 重定向到同一个文件中

cmd 2>&1 output.txt 

或者简写:

cmd &> output.txt

6. 文件黑洞

将输出流重定向至设备 /dev/null 可以直接丢弃输出内容:

cmd &> /dev/null

7. 管道

使用管道运算符可以在多个命令之间讲输入输出流引导,前一个命令的输出流可以作为后一个命令的输入流:

cat file | tac

8. 截留输出流

使用 tee 命令可以将获取到的输入流原样输出到 stdout,并且将内容写入文件:

ls -a | tee ls.txt | cat

追加的话加上参数 -a

ls -a | tee -a ls.txt | cat

tee 的文件参数如果是 -,那么这份输出的副本就会送给 stdout 输出流:

echo text | tee - 

这样子屏幕的标准输出流会输出两次 text,其中最终的管道输出一次,另一次是 tee 将输入流副本通过 - 写入了 stdin 一次。

9. 输入输出流文件

可以使用 /etc/stdin 代替 stdin,用 /dev/stdout 代替 stdout

#!/bin/bash
ls +

运行上述脚本 script.sh

./script.sh > /dev/null

这个时候屏幕会输出错误,因为错误内容是从 stderr 输出的。

这个时候我们在脚本内部将 stderr 重定向到 stdout:

#!/bin/bash
ls + 2> /dev/stdout

再次运行上述脚本 script.sh

./script.sh > /dev/null

这次错误语句在脚本外部被重定向到了 stdout,然后被丢弃,所以不会显示任何内容。

10. 输入流重定向

利用 < 输入重定向运算符,将文件内容作为输入流:

echo "Hello world!" > hello.txt
cat < hello.txt

11. 脚本直接输入内容作为标准输入

#!/bin/bash
cat<<EOF
This is a paragraph embedded in a script file.
The text embedded will directly put into stdin.
Until a single line of word 'EOF' met.
EOF

执行这个脚本,EOF 之间的内容就会输出。

这种情况如果想直接指定输出流:

#!/bin/bash
cat<<EOF > output.txt
This is a paragraph embedded in a script file.
The text embedded will directly put into stdin.
Until a single line of word 'EOF' met.
EOF

这个 EOF 只是一个自定义的文件结束符,我们可以根据实际情况制定我们自己的文件结束符,当文档输入遇到一个行完整匹配这个输出符,就可以结束输入:

cat <<!
Hello world!
This is a multiline echo.
!

自定义文件描述符

使用 exec 命令可以创建自己的文件描述符,一般文件打开模式有三种:

  • 只读模式,对应于 <r
  • 截断写入模式,对应于 >, w
  • 追加写入模式,对应于 >>, a

可以用以上三种任意一种创建文件描述符:

只读模式:
exec 3< input.txt
cat <& 3

注意,读取一次之后,3 这个文件描述符就已经到达结尾不能再用了。

截断写入模式:
exec 4> output.txt
cat input.txt >& 4
追加写入模式
exec 5>> output.txt
echo "append!" >& 5

注意:使用 exec 也可以直接修改 0/1/2 这三个文件描述符:

例如下例会将所有 stdout 的内容追加到 stdout.txt

exec >> stdout.txt

或者将所有的 stderr 内容追加到 stderr.txt

exec 2>> stderr.txt

【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2015/11/bash-shell-3.html【每日一Shell(3) 文件描述符及重定向】

发表评论

电子邮件地址不会被公开。 必填项已用*标注