本来想写一篇关于shell中的I/O重定向总结性的文章发到CU的shell版,但梳理了下思路,觉得对文件描述符也只是一知半解,为了不给别人增加阅读上的负担或知识上的误人子弟,就小写一篇发到自己的博客吧。如果你不小心通过搜索引擎看到此篇,还请指教和包涵。
文件描述符,在linux系统中,为了跟踪进程所打开的文件,对每个打个的文件分配一个非负数的整数给它。文件描述符保存了关于这个文件的所有信息。在linux系统中我们可以通过lsof来查看具体的信息。在shell中,默认会分配10(0-9)文件描述符,而默认的0(标准输入) 1(标准输出) 2(标准错误输出)。所谓的标准输入就是我们的键盘,而标准输出和标准错误输出,通常就是指屏幕。当然我们能改变这种情况,可以从文件中读取信息,可以把命令的输出到文件中。这就叫重定向。总而言之,重定向就是改变了默认的输入/输出的方式。
为了说明这种现象,我们来看ABS中一段脚本:
#!/bin/bash E_FILE_ACCESS=70 E_WRONG_ARGS=71 if [ ! -r "$1" ];then echo "Can't read from input file!" echo "Usage:$0 input-file ouput-file." exit $E_FILE_ACCESS fi if [ -z "$2" ];then echo "Need to specify oput file." exit $E_WRONG_ARGS fi exec 4<&0 #保存默认的标准输入到文件描述符4 exec < $1 #指定从脚本的第一个参数读取 exec 7>&1 #保存标准输出到文件描述符7 exec > $2 #指定标准输出为脚本的第二个参数 cat - | tr a-z A-Z exec 1<&7 7>&- #恢复默认的标准输出及关闭文件描述符7 exec 0<&4 4<&- #恢复默认的标准输入及关闭文件描述符4 exit 0
解说:以上脚本的功能就是从脚本的第一个参数中读取(而非从键盘读取),经过tr的转换后把输出发送到脚本第二个参数所指定的地方(而非发送到屏幕)。
#!/bin/bash
#此脚本借用了sed的替换功能来模拟grep中缺少替换的作用
if [ $# -lt 3 ];then
echo -n "错误:"
echo "此命令必须具有三个参数"
exit 1
fi
pattern=$1
replacement=$2
if [ -f $3 ];then
file=$3
else
echo "参数3不是一个文件"
exit 1
fi
A=:
sed -e "s$A$pattern$A$replacement$A" $file
if [ $? -ne 0 ];then
echo "似乎发生一个错误,请检查参数以符合sed的命令规则"
exit 1
fi
exit 0