linux shell脚本编程笔记(五): 重定向
I/O重定向
简述:
默认情况下始终有3个"文件"处于打开状态, stdin (键盘), stdout (屏幕), and stderr (错误消息输出到屏幕上). 这3个文件和其他打开的文件都可以被重定向. 对于重定向简单的解释就是捕捉一个文件, 命令, 程序, 脚本, 或者甚至是脚本中的代码块的输出, 然后将这些输出作为输入发送到另一个文件, 命令, 程序, 或脚本中.
每个打开的文件都会被分配一个文件描述符.stdin, stdout, 和stderr的文件描述符分别是0, 1, 和 2. 对于正在打开的额外文件, 保留了描述符3到9. 在某些时候将这些格外的文件描述符分配给stdin, stdout, 或者是stderr作为临时的副本链接是非常有用的. 在经过复杂的重定向和刷新之后需要把它们恢复成正常的样子.
文件重定向通常的用法:
COMMAND_OUTPUT >
# 重定向stdout到一个文件.
# 如果没有这个文件就创建, 否则就覆盖. ls -lR > dir-tree.list
# 创建一个包含目录树列表的文件. : > filename
# > 会把文件"filename"截断为0长度.
# 如果文件不存在, 那么就创建一个0长度的文件(与'touch'的效果相同).
# : 是一个占位符, 不产生任何输出. > filename
# > 会把文件"filename"截断为0长度.
# 如果文件不存在, 那么就创建一个0长度的文件(与'touch'的效果相同).
# (与上边的": >"效果相同, 但是在某些shell下可能不能工作.) COMMAND_OUTPUT >>
# 重定向stdout到一个文件.
# 如果文件不存在, 那么就创建它, 如果存在, 那么就追加到文件后边. # 单行重定向命令(只会影响它们所在的行):
# -------------------------------------------------------------------- >filename
# 重定向stdout到文件"filename".
>>filename
# 重定向并追加stdout到文件"filename".
>filename
# 重定向stderr到文件"filename".
>>filename
# 重定向并追加stderr到文件"filename".
&>filename
# 将stdout和stderr都重定向到文件"filename". #==============================================================================
# 重定向stdout, 一次一行.
LOGFILE=script.log echo "This statement is sent to the log file, \"$LOGFILE\"." >$LOGFILE
echo "This statement is appended to \"$LOGFILE\"." >>$LOGFILE
echo "This statement is also appended to \"$LOGFILE\"." >>$LOGFILE
echo "This statement is echoed to stdout, and will not appear in \"$LOGFILE\"."
# 每行过后, 这些重定向命令会自动"reset". # 重定向stderr, 一次一行.
ERRORFILE=script.errors bad_command1 >$ERRORFILE # 错误消息发到$ERRORFILE中.
bad_command2 >>$ERRORFILE # 错误消息添加到$ERRORFILE中.
bad_command3 # 错误消息echo到stderr,
#+ 并且不出现在$ERRORFILE中.
# 每行过后, 这些重定向命令也会自动"reset".
#============================================================================== >&
# 重定向stderr到stdout.
# 得到的错误消息与stdout一样, 发送到一个地方. i>&j
# 重定向文件描述符i 到 j.
# 指向i文件的所有输出都发送到j中去. >&j
# 默认的, 重定向文件描述符1(stdout)到 j.
# 所有传递到stdout的输出都送到j中去. < FILENAME
< FILENAME
# 从文件中接受输入.
# 与">"是成对命令, 并且通常都是结合使用.
#
# grep search-word <filename [j]<>filename
# 为了读写"filename", 把文件"filename"打开, 并且分配文件描述符"j"给它.
# 如果文件"filename"不存在, 那么就创建它.
# 如果文件描述符"j"没指定, 那默认是fd , stdin.
#
# 这种应用通常是为了写到一个文件中指定的地方.
echo > File # 写字符串到"File".
exec <> File # 打开"File"并且给它分配fd .
read -n <& # 只读4个字符.
echo -n . >& # 写一个小数点.
exec >&- # 关闭fd .
cat File # ==> 1234.67890
# 随机存储. |
# 管道.
# 通用目的的处理和命令链工具.
# 与">"很相似, 但是实际上更通用.
# 对于想将命令, 脚本, 文件和程序串连起来的时候很有用.
cat *.txt | sort | uniq > result-file
# 对所有的.txt文件的输出进行排序, 并且删除重复行,
# 最后将结果保存到"result-file"中.
将输入输出重定向与管道相结合
command < input-file > output-file
command1 | command2 | command3 > output-file
将多个输出流重定向到一个文件上:
ls -yz >> command.log >&
# 将错误选项"yz"的结果放到文件"command.log"中.
# 因为stderr被重定向到这个文件中,
#+ 所有的错误消息也就都指向那里了. # 注意, 下边这个例子就不会给出相同的结果.
ls -yz >& >> command.log
# 输出一个错误消息, 但是并不写到文件中. # 如果将stdout和stderr都重定向,
#+ 命令的顺序会有些不同.
关闭文件描述符
n<&-
#关闭输入文件描述符n. <&-
<&-
#关闭stdin. n>&-
#关闭输出文件描述符n. >&-
>&-
#关闭stdout.
子进程继承了打开的文件描述符. 这就是为什么管道可以工作. 如果想阻止fd被继承, 那么可以关掉它:
# 只重定向stderr到一个管道.
exec >& # 保存当前stdout的"值".
ls -l >& >& >&- | grep bad >&- # 对'grep'关闭fd (但不关闭'ls').
# ^^^^ ^^^^
exec >&- # 现在对于剩余的脚本关闭它.
exec
exec 命令会将stdin重定向到文件中. 从这句开始, 后边的输入就都来自于这个文件了, 而不是标准输入了(通常都是键盘输入). 这样就提供了一种按行读取文件的方法, 并且可以使用sed 和/或 awk来对每一行进行分析.
使用exec重定向标准输入:
#!/bin/bash
# 使用'exec'重定向标准输入. exec <& # 将文件描述符#6与stdin链接起来.
# 保存了stdin. exec < data-file # stdin被文件"data-file"所代替. read a1 # 读取文件"data-file"的第一行.
read a2 # 读取文件"data-file"的第二行. echo
echo "Following lines read from file."
echo "-------------------------------"
echo $a1
echo $a2 echo; echo; echo exec <& <&-
# 现在将stdin从fd #6中恢复, 因为刚才我们把stdin重定向到#6了,
#+ 然后关闭fd # ( <&- ), 好让这个描述符继续被其他进程所使用.
#
# <& <&- 这么做也可以. echo -n "Enter data "
read b1 # 现在"read"已经恢复正常了, 就是从stdin中读取.
echo "Input read from stdin."
echo "----------------------"
echo "b1 = $b1" echo exit
例如可以这样读文件:
exec <>test.sh;
#打开test.sh可读写操作,与文件描述符3绑定 while read line<&
do
echo $line;
done
#循环读取文件描述符3(读取的是test.sh内容)
exec >&-
exec <&-
#关闭文件的,输入,输出绑定
当然一般我们可以直接重定向文件到一个代码块,相当于重定向到这个代码块的标准输入。
重定向到代码块
通常我们可以将利用将代码块的输入输出重定向的方法实现一些对于文件的操作。
例如:
# while的重定向
while [ "$name" != Smith ]
do
read name
echo $name
done <"$Filename" # 以上结构也可以这样写
exec <& # 把标准输入绑定到文件描述符3,以便稍后恢复
exec <"$Filename" # 重定向标准输入为这个文件 while [ "$name" != Smith ]
do
read name
echo $name
done exec <& # 恢复标准输入
exec <&- # 关闭文件描述符3以供后续使用 # until的重定向
until [ "$name" = Smith ]
do
read name
echo "$name"
done <"$Filename" # for循环的重定向
lineCount=`wc $Filename | awk '{print $1}'` # 统计文件的行数 for name in `seq $lineCount`
do
read name
echo $name
if [ "$name" = Smith ] # 循环到Smith的时候就退出循环
then
break
fi
done <"$Filename" # if/then结构的重定向
if :
then
read name
echo "$name"
fi <"$Filename" # 这个重定向只读了文件中的一行
Here Documents
here documents是一段代码块,可以利用重定向将这个代码块传递到一个交互或者命令中。
标准的结构为:
COMMAND <<HERESTRING
...
HERESTRING
例如:
tail << HERE
a
b
HERE
输出为:
a
b
也可以用<<-来排除tab对heredocuments的影响
例如:
cat <<- HERE
a
b
HERE
输出会是
a
b
此外,here document可以使用参数替换
例如:
name="Smith"
cat << HERE
a
$name
HERE
将会输出
a
Smith
参数替换可以使用''来禁用
name="Smith"
cat << 'HERE'
a
$Smith
HERE
将会输出
a
$Smith
可以利用这种方法来产生代码,不会造成问题。
函数也可以使用here document来提供数据
function echoabc(){
read line1
echo line1
read line2
echo line2
}
echoabc << HERE
a
b
HERE
也可以输出
a
b
还可以使用here document注释代码块
例如:
: << HERE
echo a
HERE echo b
输出为:
b
相当于将here document传递给了:,不会有任何的影响。
注意here document的结束符前后都不可以有空格,否则会产生识别上的错误
here string
here string可以认为是here document的一种形式。
例如:
HERE="abcd"
tail <<< $HERE
将会输出:
abcd
相当于直接将一个string传递给了命令.
一个小陷阱:
echo "some text here" > file
cat < file > file
cat < file
sed 's/hello/hi/' file > file
上面这两个例子都会清空文件file。原因同一个:在 IO Redirection 中,stdout 与 stderr 的管道会先准备好,才会从 stdin 取资料。故而上面的两个例子都会先执行"> file"操作,即清空了文件,再执行前面的操作。这个陷阱需要额外注意。
参考资料:
https://www.jianshu.com/p/681a3a762fe5
http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=218853&page=7#pid1636825
linux shell脚本编程笔记(五): 重定向的更多相关文章
- linux shell脚本编程笔记(二): 分支结构
1.if if command then commands fi if command then commands else commands fi if command1 then command ...
- linux shell脚本编程笔记(一): 构建基本脚本
1. echo -n str 打印不换行 2. 反引号来圈住命令传入变量 eg: 生成日志文件: #!/bin/bash today=`date +%y%m%d` ls /usr/bin ...
- linux shell脚本编程笔记(四): 获取字符串长度的七种方法
获取字符串长度的七种方法 1. \${#str} 2.awk的length 备注:1) 最好用{}来放置变量2) 也可以用length($0)来统计文件中每行的长度 3.awk的NF 备注: -F为分 ...
- linux shell脚本编程笔记(三): 三种引号的区别
双引号.单引号.反引号的区别 测试用例: OPDATE=`date -d '-1 day' +%Y%m%d` ) do FILEDATE=`date -d "-$i day" +% ...
- Linux shell脚本编程(三)
Linux shell脚本编程 流程控制: 循环语句:for,while,until while循环: while CONDITION; do 循环体 done 进入条件:当CONDITION为“真” ...
- Linux shell脚本编程(二)
Linux shell脚本编程(二) 练习:求100以内所有偶数之和; 使用至少三种方法实现; 示例1: #!/bin/bash # declare -i sum=0 #声明一个变量求和,初始值为0 ...
- Linux shell脚本编程(一)
Linux shell脚本编程: 守护进程,服务进程:启动?开机时自动启动: 交互式进程:shell应用程序 广义:GUI,CLI GUI: CLI: 词法分析:命令,选项,参数 内建命令: 外部命令 ...
- Linux Shell脚本编程--Linux特殊符号大全
Linux Shell脚本编程--Linux特殊符号大全 linux_shell 特殊符号的介绍 2011
- Linux Shell脚本编程while语句
Linux Shell脚本编程while语句案例 1,每隔3秒,打印一次系统负载 #!/bin/bash while truedo uptime sleep 3done 2,把监控结果保存 ...
随机推荐
- 在CMD中使用for命令对单行字符串做分割的方法
我们都知道CMD中的for命令是执行循环命令的,数据来源可以是一个文件,一个命令的结果或一个字符串,只有这3种来源 如果是一个文件则对这个文件的所有字符串进行循环处理 如果是一个命令结果,那么对这个命 ...
- Shell排序算法和合并排序算法
Shell排序(希尔排序)算法Shell排序严格来说基于插入排序的思想,其又称为希尔排序或者缩小增量排序. Shell排序的流程:1.将由n个元素的数组分成n/2个数字序列,第1个数据和第n/2+1个 ...
- git 常用命令--抓取分支-为自己记录(二)
二:抓取分支: 多人协作时,大家都会往master分支上推送各自的修改.现在我们可以模拟另外一个同事,可以在另一台电脑上(注意要把SSH key添加到github上)或者同一台电脑上另外一个目录克隆, ...
- ZetCode PyQt4 tutorial widgets II
#!/usr/bin/python # -*- coding: utf-8 -*- """ ZetCode PyQt4 tutorial In this example, ...
- Python面试题(十二)
1.利用Python执行shell脚本取得返回结果 import subprocess result = subprocess.getoutput('dir') 答案 2.用Python将" ...
- python下的select模块使用 以及epoll与select、poll的区别
python下的select模块使用 以及epoll与select.poll的区别 先说epoll与select.poll的区别(总结) 整理http://www.zhihu.com/question ...
- Netty5.x 和3.x、4.x的区别及注意事项(官方翻译)
Netty5.x 和3.x.4.x的区别及注意事项 (官方翻译) 本文档列出了Netty5新版本中值得注意变化和新特性列表.帮助你的应用更好的适应新的版本. 不像Netty3.x和4.x之间的变化 ...
- MySQL 练习题4
1.表结构如下: #课程表 CREATE TABLE `course` ( `c_id` ) NOT NULL, `c_name` ) DEFAULT NULL, `t_id` ) DEFAULT N ...
- CCNode的属性说明
class CC_DLL CCNode : public CCObject { protected://属性列表 float m_fRotationX; ///x轴旋转角度 float m_fRota ...
- 几个与JVM相关的JDK工具:jps, jstat, jmap
在项目中遇到OOM(Out of Memory)的问题,为了分析内存和JVM的垃圾回收器GC问题,一并把JVM相关的一些工具也研究了一下: jps:Java进程查看工具,实际上它和Unix/Linux ...