Shell 有時會引用使用文件描述符(fd)的文件。我們一般使用文件描述符(fd)的范圍是數字 0~9。重定向時大于 9 的文件描述符要謹慎使用,因為它們可能與 Shell 內部使用的文件描述符沖突。
文件描述符可以包含多個數字位。例如,文件描述符 001 和 01 與文件描述符 1 是相同的。多種操作(例如,exec 命令)都可以將文件描述符與特定的文件聯系起來。
有些文件描述符是在 Shell 啟動時被建立的,這就是我們前面介紹的標準輸入、標準輸出和標注錯誤(0、1、2)文件描述符。
實例:使用 exec 命令
Bash 的內部命令 exec 的功能之一就是允許我們操作文件描述符。如果在 exec 之后沒有指定命令,則 exec 命令之后的重定向將更改當前 Shell 的文件描述符。
例如,在命令 “exec 2> file” 之后運行的所有命令,都會將其產生的錯誤信息發送到文件 file 中,就像你的命令在腳本 myscript.sh 中,而你運行的是 “./myscript.sh >2 file”。
比如,如果你想記錄腳本中的命令產生的錯誤信息,就可以在腳本的開頭使用類似如下的命令:
exec 2> errors.log
下面我們來看一個腳本文件,在這個腳本中我們想要順序地讀取文件中的每一行,并在打印每一行之后,等待用戶輸入任意鍵后繼續。
#! /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
從上面的輸出結果我們可以看到,read 語句并沒有執行:因為我們將指定的文件重定向到了 while 循環的標準輸入(文件描述符 0),即我們指定的文件將被打開以用于標準輸入的讀取,而循環中的所有命令包括 read 命令都會繼承這個文件描述符(這里是標準輸入),因此 read 將從重定向后的標準輸入讀取,而不是從默認的標準輸入設備(鍵盤)讀取。
而此時,我們就可以使用 exec 命令對腳本稍加改動,來實現我們想要的功能,改動后的腳本將類似如下所示:
#! /bin/bash
if [ $# -lt 1 ]; then
echo "Usage: $0 FILEPATH"
exit
fi
# 將腳本的第一個參數作為輸入文件,并制定一個文件描述符 3
exec 3< $1
while read -u 3 line
do
echo $line
read -p "Press any key: " -n 1
done
# 關閉文件描述符 3
exec 3<&-
在上述腳本中,我們使用的 “read -u 3 line” 命令,為 read 指定從指定的描述符中讀取數據。
上述腳本的運行效果
本文參考自 《Linux Shell命令行及腳本編程實例詳解 》