【转】linux shell I/O重定向小结
转自:http://molinux.blog.51cto.com/2536040/469554
材料总结,大部分内容及示例摘自《Advanced Bash-Scripting Guide》中chapt:An in-depth exploration of the art of shell scripting;需要详细请自行参看。
对于重定向简单的解释就是捕捉一个文件, 命令, 程序, 脚本, 或者甚至是脚本中的代码块的输出, 然后将这些输出作为输入发送到另一个文件, 命令, 程序, 或脚本中.
默认情况下始终有3个"文件"处于打开状态, stdin (键盘), stdout (屏幕), andstderr (错误消息输出到屏幕上).
每个打开的文件都会被分配一个文件描述符.stdin, stdout, 和stderr的文件描述符分别是0, 1, 和 2. 对于正在打开的额外文件, 保留了描述符3到9. 在某些时候将这些格外的文件描述符分配给stdin, stdout, 或者是stderr作为临时的副本链接是非常有用。并且在经过复杂的重定向和刷新之后需要把它们恢复成正常的样子
文件描述符:
表示范围: 0-9
0-2:是系统定义好的。
0:代表STDIN,标准输入
1:代表STDOUT,是标准输出
2:代表STDERR,是标准错误输出
3-9:系统未定义,需要使用的可以自己定义使用
- COMMAND_OUTPUT >
- # 重定向stdout到一个文件.
- # 如果没有这个文件就创建, 否则就覆盖.
- COMMAND_OUTPUT >>
- # 重定向stdout到一个文件.
- # 如果文件不存在, 那么就创建它, 如果存在, 那么就追加到文件后边.
- # 单行重定向命令(只会影响它们所在的行):
-
- #==========================================================
- 1>filename
- # 重定向stdout到文件"filename".
- 1>>filename
- # 重定向并追加stdout到文件"filename".
- 2>filename
- # 重定向stderr到文件"filename".
- 2>>filename
- # 重定向并追加stderr到文件"filename".
- &>filename
- # 将stdout和stderr都重定向到文件"filename"
- #============================================================
- 2>&1
# 重定向stderr到stdout.
# 得到的错误消息与stdout一样, 发送到一个地方.
i>&j
# 重定向文件描述符i 到 j.
# 指向i文件的所有输出都发送到j中去.
>&j
# 默认的, 重定向文件描述符1(stdout)到 j.
# 所有传递到stdout的输出都送到j中去.
0< FILENAME
< FILENAME
# 从文件中接受输入.
# 与">"是成对命令, 并且通常都是结合使用.
#
# grep search-word <filename
[j]<>filename
# 为了读写"filename", 把文件"filename"打开, 并且分配文件描述符"j"给它.
# 如果文件"filename"不存在, 那么就创建它.
# 如果文件描述符"j"没指定, 那默认是fd 0, stdin.
#
# 这种应用通常是为了写到一个文件中指定的地方. - 例:
echo 1234567890 > File # 写字符串到"File".
exec 3<> File # 打开"File"并且给它分配fd 3.
read -n 4 <&3 # 只读4个字符.
echo -n . >&3 # 写一个小数点.
exec 3>&- # 关闭fd 3.
cat File # ==> 1234.67890
# 随机存储.
可以将输入输出重定向的多个实例书写到一行命令中
#command < input-file > output-file
可以将多个输出流重定向到一个文件上:
1 ls -yz >> command.log 2>&1 # 将错误选项"yz"的结果放到文件"command.log"中. # 因为stderr被重定向到这个文件中, #+ 所有的错误消息也就都指向那里了. # 注意, 下边这个例子就不会给出相同的结果. ls -yz 2>&1 >> command.log # 输出一个错误消息, 但是并不写到文件中. # 如果将stdout和stderr都重定向, # 命令的顺序会有些不同.
关闭文件描述符
- n<&-
-
关闭输入文件描述符n.
- 0<&-, <&-
-
关闭stdin.
- n>&-
-
关闭输出文件描述符n.
- 1>&-, >&-
-
关闭stdout.
使用exec:
exec <filename
命令会将stdin重定向到文件中. 从这句开始, 后边的输入就都来自于这个文件了, 而不是标准输入了(通常都是键盘输入). 这样就提供了一种按行读取文件的方法, 并且可以使用 sed 和 / 或 awk 来对每一行进行分析.
exec >filename
命令将会把stdout重定向到一个指定的文件中. 这样所有的命令输出就都会发向那个指定的文件, 而不是stdout.
示例:exec重定向stdout
- #!/bin/bash
- # reassign-stdout.sh
- LOGFILE=logfile.txt
- exec 6>&1 # 将fd 6 与stdout相连接.
- # 保存stdout.
- exec > $LOGFILE # stdout就被文件"logfile.txt"所代替了
- #---------------------------------------------------------
- # 在这块中所有命令的输出就都发向文件 $LOGFILE.
- echo -n "Logfile: "
- date
- echo "-------------------------------------"
- echo
- echo "Output of \"ls -al\" command"
- echo
- ls -al
- echo; echo
- echo "Output of \"df\" command"
- echo
- df
- # ----------------------------------------------------------- #
- exec 1>&6 6>&- # 恢复stdout, 然后关闭文件描述符6.
- echo
- echo "== stdout now restored to default == "
- echo
- ls -al
- echo
- exit 0
示例:exec重定向stdout及stdin
- #!/bin/bash
- # upperconv.sh
- # 将一个指定的输入文件转换为大写.
- E_FILE_ACCESS=70
- E_WRONG_ARGS=71
- if [ ! -r "$1" ] # 判断指定的输入文件是否可读?
- then
- echo "Can't read from input file!"
- echo "Usage: $0 input-file output-file"
- exit $E_FILE_ACCESS
- fi # 即使输入文件($1)没被指定
- #+ 也还是会以相同的错误退出(为什么?).
- if [ -z "$2" ]
- then
- echo "Need to specify output file."
- echo "Usage: $0 input-file output-file"
- exit $E_WRONG_ARGS
- fi
- exec 4<&0
- exec < $1 # 将会从输入文件中读取.
- exec 7>&1
- exec > $2 # 将写到输出文件中.
- # 假设输出文件是可写的(添加检查?).
- # -----------------------------------------------
- cat - | tr a-z A-Z # 转换为大写.
- # ^^^^^ # 从stdin中读取.Reads from stdin.
- # ^^^^^^^^^^ # 写到stdout上.
- # 然而, stdin和stdout都被重定向了.
- # -----------------------------------------------
- exec 1>&7 7>&- # 恢复 stout.
- exec 0<&4 4<&- # 恢复 stdin.
- # 恢复之后, 下边这行代码将会如期望的一样打印到stdout上.
- echo "File \"$1\" written to \"$2\" as uppercase conversion."
- exit 0
注:使用文件描述符5可能会引起问题. 当Bash使用exec创建一个子进程的时候, 子进程会继承fd5. 最好还是不要用fd5