shell 與使用者互動
bashshell如何獲取命令列引數(新增到命令後的資料)、命令列選項(確定命令列為的英文字母)、鍵盤輸入資料?
操作命令列引數
1讀取引數
bash shell用位置引數變數(positional parameter)儲存命令列輸入的所有引數,包括程式名。其中,$0表示程式名,$1表示第1個引數,$2表示第2個引數,...,$9表示第9個引數。如果引數個數多於9個,必須如下表示變數:${10},${11},...
for((count = 1; count <= $1; count++))
do
echo The number is $count.
done
echo $1, $2, $10, $15
2讀取程式名
首先想到的是利用$0,但是$0獲取的檔名包括./以及路徑等字首資訊,如下:
echo The command entered is: $0
# 執行:./
# 輸出:The command entered is: ./14.sh
如果想僅得到檔名,而不包含./,可以使用basename命令:
name=`basename $0`
echo The command entered is: $name
# 執行:./
# 輸出:The command entered is: 14.sh
3特殊變數
$#表示命令列引數的個數:
params=$#
echo The number of params is: $params
for((i = 1; i <= params; i++))
do
echo The param is: $i
done
那麼很自然地,${$#}表示最後一個變數的值,如下程式:
params=$#
echo The number of params is: $params
echo The last parameter is: ${$#}

這是怎麼回事呢?原來在花括號內不能使用$符號,而是以!來代替$工作:
params=$#
echo The number of params is: $params
echo The last parameter is: ${!#}

如果想獲取所有的引數,當然可以利用$#和迴圈逐個遍歷。也可以利用如下兩個特殊變數:$*將所有的命令列引數看作一個整體儲存,而[email protected]將命令列中以空格間隔的引數單獨儲存,如下:
count=1
for param in "$*"
do
echo "\$* parameter $count = $param"
count=$[ $count + 1 ]
done
count=1
for param in "[email protected]"
do
echo "\[email protected] parameter $count = $param"
count=$[ $count + 1 ]
done
4移動變數命令shift
shift命令用於將後一個變數的值移到前一個變數上,即$3的值移到$2,$2的值移到$1,$1的值被刪除。 注:變數$0的值不會被替換。該命令可以使得在不需要知道有多少個引數的情況下即可遍歷所有引數:
count=1
while [ -n "$1" ]
do
echo "parameter $count = $1"
count=$[ $count + 1 ]
shift
done
注:使用shift命令移除的引數值是無法恢復的,也可以使用shift移到多位,如:shift2。

操作命令列選項
1查詢選項
可以判斷命令列引數是否存在有效選項:
#! /bin/bash
# extracting command line options as parameters
while [ -n "$1" ]
do
case "$1" in
-a)
echo "found the -a option";;
-b)
echo "found the -b option";;
-c)
echo "found the -c option";;
*)
echo "$1 is not an option";;
esac
shift
done
在Linux中,命令列選項和引數的分離使用--符號,shell將--前邊的引數作為選項來處理。如下指令碼可以有效地分離出選項和引數:
#! /bin/bash
# extracting command line options as parameters
while [ -n "$1" ]
do
case "$1" in
-a)
echo "found the -a option";;
-b)
echo "found the -b option";;
-c)
echo "found the -c option";;
--)
break;;
*)
echo "$1 is not an option";;
esac
shift
done
shift # 確保跳出while迴圈後,將--符號移除掉
count=1
for param in [email protected]
do
echo "parameter $count: $param"
count=$[ $count + 1 ]
done
如何處理帶有引數值的選項呢?比如,./22.sh-a-bbenxin-c-d
#! /bin/bash
# extracting command line options as parameters
while [ -n "$1" ]
do
case "$1" in
-a)
echo "found the -a option";;
-b)
param="$2"
echo "found the -b option with parameter value $param"
shift 2;;
-c)
echo "found the -c option";;
--)
shift
break;;
*)
echo "$1 is not an option";;
esac
shift
done
count=1
for param in "[email protected]"
do
echo "parameter $count: $param"
count=$[ $count + 1 ]
done
合併選項時可以使用getopt命令,格式如下:
getoptoptionsoptstringparameters
options定義了命令列中有效的選項字母以及哪些選項字母需要附加引數值等(在需要附加引數值的選項字母后加一個冒號),如getoptab:cd-a-bbenxin-cdtuzibenxintuzi,optstring定義了4個有效字母:a、b、c、d,並且說明了選項b需要附帶引數值。getopt命令自動將-cd拆分成-c和-d兩個選項,並且用雙破折號--隔開命令列中的額外引數。

2選項的標準化約定
| 選項 | 說明 |
| -a | 顯示所有物件 |
| -c | 生成一個計數 |
| -d | 指定一個目錄 |
| -e | 擴充套件一個物件 |
| -f | 指定輸入檔案 |
| -h | 顯示命令幫助 |
| -i | 忽略文字大小寫 |
| -l | 產生輸出的長格式版本 |
| -n | 使用非互動模式(批量) |
| -o | 指定輸出檔案 |
| -q | 以安靜模式執行 |
| -r | 遞迴處理目錄或檔案 |
| -s | 以安靜模式執行 |
| -v | 生成詳細輸出 |
| -x | 排除某個物件 |
| -y | 對所有問題回答yes |
操作鍵盤輸入
1基本的讀取
read命令接受從鍵盤或檔案描述符中的輸入資料,將其儲存到一個指定變數中。使用-p選項可以指定輸入提示資訊,如下所示:
#! /bin/bash
# testing the read option
read -p "Please enter your name: " name
echo "Hello $name."
read命令中,可以根據需要將輸入的資料儲存在多個變數中,如果指定的變數比較少,那麼最後一個變數將包含餘下的所有輸入,如下所示:
#! /bin/bash
# testing the read option
read -p "Enter the values: " val1 val2 val3
echo "$val1"
echo "$val2"
echo "$val3"
注:如果使用read命令時不指定變數,那麼read將其接收的任何資料都放到環境變數REPLY中。
2輸入超時
使用read命令時,指令碼會一直等待使用者輸入資料,如果想設定等待時間,使用-t選項即可指定一個計時器,當計時器超時後,read命令會返回一個非零狀態碼。
if read -t 5 -p "Please enter your name: " name
then
echo "Hello $name."
else
echo
echo "Sorry, too slow"
fi
3隱藏輸入顯示
當輸入敏感資訊時,比如密碼,不希望顯示在螢幕上,那麼可以使用read的-s選項,-s選項的功能是將輸入文字顏色設定為與背景色一樣:
#! /bin/bash
# testing the read option
read -s -p "Enter your password: " passwd
echo
echo "Is your password really $passwd?"
4從檔案中讀取
read每次從檔案中讀取一行資料,當檔案中沒有資料時,read命令返回非零狀態碼。最常見的方法是將cat命令執行後的結果通過管道傳給含有read的while語句,如下:
#! /bin/bash
# testing the read option
count=1
cat 25.sh | while read line
do
echo "Line $count: $line"
count=$[ $count + 1 ]
done
echo "Finished processing the file"
