文件描述符
#文件描述符来标识每个文件对象,唯一的标识会话中打开的文件
#0 stdin 1 stdout 2 stderr
#使用<时,Linux会用重定向指定的文件替换标准输入文件描述符
#命令行中只输入cat命令,它会接受stdin 的输入
#也可以使用重定向符号接受非stdin的输入
cat < testfile
#输出重定向来改变输出,将显示到显示器的输出定向到指定的重定向文件
ls -l > test2
#追加数据
who >> test2
#shell处理错误消息和处理普通输出是分开的
#默认情况下,stdout,stderr文件描述符指向同样的地方,显示器
#重定向错误
#只重定向错误,2>是紧连在一起的
ls -al badfile 2> test4
#重定向错误和数据
#在重定向的每个数据前添加对应的文件描述符,将它们指向对应的保存数据的输出文件
ls -al test test2 test3 badtest 2> test6 1> test7
#同样也可以将stderr和stdout输出重定向到同一个输出文件
ls -al test test2 test3 badtest &> test7
#bash shell会自动给错误消息分配较标准输出来说更高的优先级
#这样就可以在一处地方查看错误消息了```
###脚本中重定向输出
用stdout和stderr文件描述符来在多个位置生成输出,重定向相应的文件描述符
临时重定向
在脚本中生成错误消息,将某一行输出重定向到stderr
echo "this is an error message" >&2
所以如果脚本重定向了stderr,就会将上条消息输出到重定向的文件
./test8 2> test9```
永久重定向
#exec命令使shell在脚本执行期间重定向某个特定文件描述符
#重定向每个echo语句
exec 1>testout
echo "this is a test"
#exec命令会启动一个新shell并且将stdout文件描述符重定向到文件
#脚本中发给stdout的所有输出都会被重定向到文件
exec 2>testerror
echo "this is the start of the script"
exec 1>testout
echo "i love you"
echo "but this should go to the testerror file" >&2
#因此这里testout会包含正常信息,testerror则包含错误信息
#在定义1>testout之前的echo还是会输出到屏幕上的```
###在脚本中重定向输入
exec命令将stdin重定向到linux系统上的文件中
!/bin/bash
exec 0< testfile
count=1
while read line;do
echo "line #$count: $line"
count=$[ $count + 1 ]
done
读取日志文件的最简单办法```
创建输出文件描述符
#shell中最多可以有9个打开的文件描述符,另外6个是3-8
exec 3>test13out
echo "this should display on the monitor"
echo "and this should be stored in the file" >&3
echo "then this should be back on the monitor"
#可以使用exec命令来输出追加到现有文件
exec 3>>test13out```
###重定向文件描述符
将文件描述符3重定向到文件描述符1的位置,也就是显示器
类似于引用,显示器的引用,重定向文件的引用
exec 3>&1
将文件描述符1重定向到文件,但是3仍然指向显示器
exec 1>test14out
echo "this should store in the output file"
echo "along with this line"
将1重定向3的位置,也就是显示器
exec 1>&3
echo "now things should be back to normal"```
创建输入文件描述符
#先将stdin文件描述符保存到另外一个文件描述符,读取完重定向文件后再恢复
exec 6<&0
exec 0< testfile
count=1
while read line;do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
exec 0<&6
read -p "are you done now?" answer
case $answer in
y|Y) echo "goodbye";;
N|n) echo "sorry, this is the end";;
esac```
###创建读写文件描述符
使用同一个文件描述符来从文件中读写数据
exec 3<> testfile
read line <&3
echo "Read: $line"
echo "this is a test line" >&3
因为shell中会维护一个读写文件的位置指针
因此读取之后,指针的位置将作为下一次读写的位置
如果写入的话,就会从这个位置开始覆盖原有的数据```
关闭文件描述符
#shell会在脚本退出时自动关闭它们
#手动关闭文件描述符
exec 3>&-
#下面是一个例子,最后会出现错误,一旦关闭了,就不能再使用了
exec 3> test17file
echo "this is a test line of data" >&3
exec 3>&-
echo "this won't work" >&3```
###列出打开的文件描述符
lsof -a -p $$ -d 0,1,2
-a选项是对后面两个选项的结果执行布尔and运算
-p指定进程PID,$$表示当前进程的PID
-d表示允许指定要显示的文件描述符的个数
FD那一列中,数字表示文件描述符,u表示读写,w表示写,r表示读```
阻止命令输出
ls -al > /dev/null
#阻止任何错误消息但是不保存
ls -al badfile test16 2> /dev/null
#也可以在输入重定向将/dev/null作为输入文件
#从而快速移除现有的文件中的数据而不用先删除文件再创建,bingo
cat /dev/null > testfile```
###创建本地临时文件
mktemp会在本地目录中创建一个临时文件
指定文件名模板,
mktemp testing.XXXXXX
mktemp会用6个字符码替换这6个X,保证文件名在目录中是唯一的,返回文件名
将文件名保存到变量中,就可以在后面脚本中引用了
tempfile=mktemp test19.XXXXXX
exec 3>$tempfile
echo "this script writes to temp file $tempfile"
echo "this is the first line" >&3
echo "this is the second line" >&3
exec 3>&-
echo "done creating temp file, the contents are:"
cat $tempfile
rm -f $tempfile 2> /dev/null```
在/tmp目录创建临时文件
#-t选项会在系统的临时目录创建文件,返回全路径
mktemp -t test.XXXXXX
#比如返回/tmp/test.XG3374
tempfile=`mktemp -t tmp.XXXXXX`
echo "this is a test file" > $tempfile
echo "this is the second line" >> $tempfile
echo "the temp file is located at: $tempfile"
cat $tempfile
rm -f $tempfile```
###创建临时目录
-d选项使其创建一个临时目录
tempdir=mktemp -d dir.XXXXXX
cd $tempdir
tempfile1=mktemp temp.XXXXXX
tempfile2=mktemp temp.XXXXXX
exec 7> $tempfile1
exec 8> $tempfile2
echo "sending data to directory $tempdir"
echo "this is a test line of data for $tempfile1" >&7
echo "this is a test line of data for $tempfile2" >&8```
tee命令
#将stdin过来的数据重定向
date | tee testfile
#默认情况下,tee命令会在每次使用时覆盖输出文件内容
#使用-a来将数据追加过去
date | tee -a testfile```