Shell 有時(shí)會(huì)引用使用文件描述符(fd)的文件。我們一般使用文件描述符(fd)的范圍是數(shù)字 0~9。重定向時(shí)大于 9 的文件描述符要謹(jǐn)慎使用,因?yàn)樗鼈兛赡芘c Shell 內(nèi)部使用的文件描述符沖突。
文件描述符可以包含多個(gè)數(shù)字位。例如,文件描述符 001 和 01 與文件描述符 1 是相同的。多種操作(例如,exec 命令)都可以將文件描述符與特定的文件聯(lián)系起來。
有些文件描述符是在 Shell 啟動(dòng)時(shí)被建立的,這就是我們前面介紹的標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)注錯(cuò)誤(0、1、2)文件描述符。
實(shí)例:使用 exec 命令
Bash 的內(nèi)部命令 exec 的功能之一就是允許我們操作文件描述符。如果在 exec 之后沒有指定命令,則 exec 命令之后的重定向?qū)⒏漠?dāng)前 Shell 的文件描述符。
例如,在命令 “exec 2> file” 之后運(yùn)行的所有命令,都會(huì)將其產(chǎn)生的錯(cuò)誤信息發(fā)送到文件 file 中,就像你的命令在腳本 myscript.sh 中,而你運(yùn)行的是 “./myscript.sh >2 file”。
比如,如果你想記錄腳本中的命令產(chǎn)生的錯(cuò)誤信息,就可以在腳本的開頭使用類似如下的命令:
exec 2> errors.log
下面我們來看一個(gè)腳本文件,在這個(gè)腳本中我們想要順序地讀取文件中的每一行,并在打印每一行之后,等待用戶輸入任意鍵后繼續(xù)。
#! /bin/bash
if [ $# -lt 1 ]; then
echo "Usage: $0 FILEPATH"
exit
fi
file=$1
while read -r line
do
echo $line
read -p "Press any key" -n 1
done < $file

從上面的輸出結(jié)果我們可以看到,read 語句并沒有執(zhí)行:因?yàn)槲覀儗⒅付ǖ奈募囟ㄏ虻搅?while 循環(huán)的標(biāo)準(zhǔn)輸入(文件描述符 0),即我們指定的文件將被打開以用于標(biāo)準(zhǔn)輸入的讀取,而循環(huán)中的所有命令包括 read 命令都會(huì)繼承這個(gè)文件描述符(這里是標(biāo)準(zhǔn)輸入),因此 read 將從重定向后的標(biāo)準(zhǔn)輸入讀取,而不是從默認(rèn)的標(biāo)準(zhǔn)輸入設(shè)備(鍵盤)讀取。
而此時(shí),我們就可以使用 exec 命令對(duì)腳本稍加改動(dòng),來實(shí)現(xiàn)我們想要的功能,改動(dòng)后的腳本將類似如下所示:
#! /bin/bash
if [ $# -lt 1 ]; then
echo "Usage: $0 FILEPATH"
exit
fi
# 將腳本的第一個(gè)參數(shù)作為輸入文件,并制定一個(gè)文件描述符 3
exec 3< $1
while read -u 3 line
do
echo $line
read -p "Press any key: " -n 1
done
# 關(guān)閉文件描述符 3
exec 3<&-
在上述腳本中,我們使用的 “read -u 3 line” 命令,為 read 指定從指定的描述符中讀取數(shù)據(jù)。
上述腳本的運(yùn)行效果

本文參考自 《Linux Shell命令行及腳本編程實(shí)例詳解 》