shell指令碼使用者輸入處理——shell程式設計學習_七
在Linux作業系統中,使用者輸入一般分為兩類:
命令列引數
這是在命令啟動時將資料傳遞,命令列引數形式一般包括:命令、選項、引數
選項用來定義使用者的行為
引數用來向命令傳遞特定的資料
如:
[[email protected] input]# ls -a test_1.sh test_1.sh //即瞬間生成程序,執行完瞬間釋放。引數的傳遞應該和命令的進行同時
執行時輸入
這種是在命令啟動之後,將資料傳遞。
如:
[[email protected] input]# cat test_1.sh test_1.sh fsx fsx //即先生成命令程序,然後在傳入資料,進行處理。
命令列引數的使用
讀取引數
引數之間使用空格進行分割
在指令碼中,使用位置引數的特殊變數,來進行引數讀取:$+position。
如:$0
$1
$2
.......
其中,$0表示的是程式名
真正的引數是從$1開始的
到了第十個引數,就需要${10}這樣的形式來表示了。
示例:
[[email protected] input]# cat test_1.sh #!/bin/bash echo "the #1 param is: $1"//這裡第一個引數必須是$1、否則核心不識別 echo "the #2 param is: $2" SUM=$[ $1+$2] echo "the restult is $SUM" [[email protected] input]# bash test_1.sh 2 3 the #1 param is: 2 the #2 param is: 3 the restult is 5
如果要用第一個引數和第五個引數,就要:
[[email protected] input]# cat test_2.sh //具體程式碼 #!/bin/bash echo "the #1 param is: $5" echo "the #2 param is: $1" SUM=$[ $1+$5] echo "the restult is $SUM" [[email protected]input]# bash test_2.sh 2 3//這裡只串進來了兩個引數,所以無法識別到第五個引數 the #5 param is: the #1 param is: 2 test_2.sh: line 6: 2+: syntax error: operand expected (error token is "+") the restult is [[email protected] input]# bash test_2.sh 2 3 1 2 5//這裡串進來了五個引數,第五個引數值為5,所以輸出的是2+5 the #5 param is: 5 the #2 param is: 2 the restult is 7
$0是我們輸入的第一個引數,即檔名(包含路徑)
[[email protected] mnt]# cat input/test_3.sh #!/bin/bash echo "the bash file name $0" echo "the #1 param is: $3" echo "the #2 param is: $2" echo "the #2 param is: $1" SUM=$[ $1+$2 ] echo "the restult $1+$2 is $SUM" [[email protected] mnt]# pwd /mnt [[email protected] mnt]# bash input/test_3.sh 1 2 3 the bash file name input/test_3.sh the #1 param is: 3 the #2 param is: 2 the #2 param is: 1 the restult 1+2 is 3
有時候我們只想獲取命令(檔名),我們就需要引入basename
關鍵字
[[email protected] mnt]# cat input/test_3.sh #!/bin/bash echo "the bash file name ` basename $0`" echo "the #1 param is: $3" echo "the #2 param is: $2" echo "the #2 param is: $1" SUM=$[ $1+$2 ] echo "the restult $1+$2 is $SUM" [[email protected] mnt]# bash input/test_3.sh 1 2 3 the bash file name test_3.sh//有了`basename`關鍵字,這是的name值是命令(檔名)名字 the #1 param is: 3 the #2 param is: 2 the #2 param is: 1 the restult 1+2 is 3 [[email protected] mnt]# pwd /mnt 這是一個很有意義的關鍵字
使用basename
的一個好處:可以在一個shlle指令碼中,實現多種命令,用軟連線對指令碼重新命名,呼叫不同的軟連線實現不同功能。
示例:編輯shell指令碼,test_4.sh
[[email protected] input]# cat test_4.sh #!/bin/bash name=`basename $0` if [ $name = "add" ]//當命令(執行的指令碼名)名字為 add 時,執行 if 語句裡面的命令,即加法 then result=$[ $1+$2 ] elif [ $name = "minus" ]//當命令(執行的指令碼名字)名字為 minus 時,執行 elif 語句裡面的命令,即減法 then result=$[ $1-$2 ] fi echo "the $name result is $result"
然後製作兩個軟連線,分別指向test_4.sh,一個命名為add
,一個命名為minus
,分別執行
[[email protected] input]#ln -s test_4.sh add [[email protected] input]#ln -s test_4.sh minus [[email protected] input]# ./add 4 5//使用add時,加法 the add result is 9 [[email protected] input]# ./minus 4 5//使用minus時,減法 the minus result is -1 [[email protected] input]# ll//==ls -l total 16 lrwxrwxrwx 1 root root 9 Apr 16 08:12 add -> test_4.sh lrwxrwxrwx 1 root root 9 Apr 16 08:12 minus -> test_4.sh -rw-r--r-- 1 root root 177 Apr 16 07:26 test_3.sh //通過一個指令碼實現兩個命令
幾個特殊的變數
Linux規定了一些預設的變數,如:
$#:引數計數
$*:所有引數
[email protected]:引數列表
示例:
[[email protected] input]# bash test_5.sh 1 2 3 4 a 5//$# 1 2 3 4 a//[email protected] 1 2 3 4 a//$* [[email protected] input]# cat test_5.sh #!/bin/bash echo $# echo [email protected] echo $* //[email protected]和$*在這裡有什麼區別呢?
示例2:
[[email protected] input]# bash test_6.sh 1 2 3 4 a 5 1 2 3 4 a 1 2 3 4 a $* param = 1 2 3 4 a//$*把所有引數當成一個字串來處理,存在的是一個變數 [email protected] param = 1//[email protected]吧引數當成以一個列表 [email protected] param = 2 [email protected] param = 3 [email protected] param = 4 [email protected] param = a [[email protected] input]# cat test_6.sh //具體程式碼 #!/bin/bash echo $# echo [email protected] echo $* for var in "$*" do echo "\$* param = $var" done for var in "[email protected]" do echo "\[email protected] param = $var" done
命令列引數的處理
條件判斷
使用者的輸入是千奇百怪的,為了避免使用者輸入不匹配,並且給使用者更好的體驗,使用判斷對命令列引數進行基本的驗證是很有必要的。
使用條件判斷對引數個數進行規定,如果不是條天判斷中的個數,則直接返回錯誤,結束程式。
[[email protected] input]# bash test_7.sh 2//當只有一個引數的時候,輸出判斷結果 input error [[email protected] input]# cat test_7.sh #!/bin/bash if [ $# -lt 2 ]//對引數的基本驗證,本shell指令碼要求是兩個引數 then echo "input error" exit fi echo "the #1 param is: $2" echo "the #2 param is: $1" SUM=$[ $1+$2] echo "the restult is $SUM"
shift
命令:用來移動引數,來進行多引數處理。不斷向前移動位置引數。
[[email protected] read]# cat sum.sh #!/bin/bash result=0 while [ -n "$1" ] do result=$[ $result + $1 ] shift//shift每次將所有引數向前移動一次,原本的$1就被丟棄,$2變成$1......達到使用一個$1就遍歷所有的引數 done echo "total number is: $result" [[email protected] read]# bash sum.sh 123 45 1 4325 total number is: 4494
shift
類似於主動遍歷所有引數,將每個引數都當成$1
執行一次。
進行命令列選項處理
在Linux中,選項是一種對命令列為進行設定的通用方式。通常是-字母
處理簡單選項
這樣很適合linux中的agent,(start|restart|stop|reload)
[[email protected] read]# cat test_6.sh #!/bin/bash while [ -n "$1" ] do case "$1" in -a) echo "使用選項 -a";; -b) echo "使用選項 -b";; -v) echo "使用選項 -v";; esac shift done [[email protected] read]# bash test_6.sh -v 使用選項 -v [[email protected] read]# bash test_6.sh -a 使用選項 -a
引數和選項進行隔離
使用--
對引數和選項進行分離,具體實現:
[[email protected] read]# cat test_7.sh #!/bin/bash while [ -n "$1" ] do case "$1" in -a) echo "input -a";; -b) echo "input -b";; -v) echo "input -v";; --) shift//當遇到--前,一致遍歷$1,一遇到`--`跳出while迴圈 break;; esac shift//跳出迴圈後,繼續shift遍歷 done echo "input other is $*"//輸出其他的引數
執行結果:
[[email protected] read]# bash test_7.sh -a -v -- fsx 123 input -a input -v input other is fsx 123
處理帶值的選項
通常,我們會在選項後面加入一些值,實現示例:
[[email protected] read]# cat test_8.sh #!/bin/bash while [ -n "$1" ] do case "$1" in -a) echo "input -a";; -b) value="$2" //匹配到-b後,定義一個$2變數儲存下一個引數 echo "input -b,result is $value" //然後輸出$2 shift;;//因為這$1下一個引數被$2拿走,shift要向前走一次,才能完成後續遍歷 -v) echo "input -v";; --) shift break;; esac shift done echo "input other is $*"
引數合併問題
實際情況中,我們還會遇到選項合併的情況,如:-av
這時候使用getopt
命令來實現
[[email protected] read]# getopt abcd -b -acd //abcd是一個passing的語句,指定能夠解析哪些選項,這裡就是說明可以解析a、b、c、d -b -a -c -d -- //
--
是結束的標誌[[email protected] read]# getopt abcd -bacd -b -a -c -d --
[[email protected] read]# getopt ab:cd -b fsx -acd qpy hh //某一個選項後面有冒號,表示這個選項後面可以帶值。 -b fsx -a -c -d -- qpy hh //這裡進行了正確的匹配,字串
fsx
屬於-b
的值
指令碼實現示例:
[[email protected] read]# cat test_9.sh #!/bin/bash set -- `getopt -q ab:v "[email protected]"`//使用set -- 將getopt的結果賦給命令列引數,之後就可以繼續使用位置引數來訪問已經解析後的變數。-q是--quit的意思,指不會輸出getopt遇到的錯誤。[email protected]原來命令列引數的集合 while [ -n "$1" ] do case "$1" in -a) echo "input -a";; -b) value="$2" echo "input -b,result is $value" shift;; -v) echo "input -v";; --) shift break;; esac shift done echo "input other is $*"
測試:
[[email protected] read]# bash test_9.sh -b fsx -av -- qpy hh//這裡-av可以放在以其,解析時分開 input -b,result is 'fsx' input -a input -v input other is 'qpy' 'hh' //如果-b後面的值包含空格怎麼辦?使用雙引號不管用,如: [[email protected] read]# bash test_9.sh -b "fsx qpy" -av -- qpy hh input -b,result is 'fsx//並沒有正確解析值,getopt不能解析空格值,這時需要使用getopts命令 input -a input -v input other is 'qpy' 'hh'
引數合併問題二
getopt不能解析有空格的值,這時需要使用getopts命令
getopts
是getopt
的升級版本,使用方法大不相同
示例:
[[email protected] read]# cat getopts.sh #!/bin/bash while getopts ab:v opt #直接通過getopts獲取,ab:v和getopt一樣,把解析出來的選項賦值給opt變數 do case "$opt" in a) echo "input -a";; b) echo "input -b,result is $OPTARG";; #OPTARG是一個全域性環境變數,是選項引數的意思。可以訪問選項引數值 v) echo "input -v";; *) echo "unknow options $opt";; #getopts不需要"--" esac done shift $[ $OPTIND +1 ]#OPTIND是解析的選項個數,也是一個全域性環境變數。這裡跳到所有引數結束,去訪問getopts結束作用後,後面的引數 count=1//列印每輸入的每一行引數 for param in "[email protected]" do echo "param #$count is : $param" count=$[ $count + 1] done
執行測試:
[[email protected] read]# bash getopts.sh -av -b "fsx 123" qpy input -a input -v input -b,result is fsx 123 param #1 is : -av param #2 is : -b param #3 is : fsx 123 param #4 is : qpy
在shell中,規定了一些通用的選項含義,依次來進行一些相通的命令的操作
選項 | 含義 |
---|---|
-a | 顯示所有物件 |
-c | 生成一個計數 |
-d | 指定一個目錄 |
-e | 擴充套件一個物件 |
-f | 指定讀取資料的檔案 |
-h | 顯示命令的幫助資訊 |
在指令碼執行時獲取輸入
在指令碼中獲取輸入,可以使用read
命令
read
的基本讀取
示例:
[[email protected] read]# bash test_1.sh type your input fsx you type fsx [[email protected] read]# cat test_1.sh #!/bin/bash echo "type your input" read input//從標準輸入中讀取一個引數,並且儲存到變數input中 echo "you type $input"
read
的處理超時
示例:
這裡使用read
的-t
引數,指定超時時間
[[email protected] read]# cat test_2.sh #!/bin/bash if read -t 2 -p "type your input " input//如果超時兩秒鐘沒有輸入,則執行else中的命令 then echo "you type $input" else echo " timeout" fi
執行結果:
[[email protected] read]# bash test_2.sh //如果2秒中內,沒有輸入,則輸出timeout type your input timeout [[email protected] read]# bash test_2.sh //2秒內輸入,則執行if中的語句 type your input fsx you type fsx
不回顯的read
讀取
示例:
這裡使用read
的-s
引數,設定輸入不回顯
[[email protected] read]# bash test_3.sh type your input you type fsx123 [[email protected] read]# cat test_3.sh #!/bin/bash echo "type your input" read -s passwd//-s指定,使用者在終端輸入資料,不回顯,儲存到passwd變數中 echo "you type $passwd"//執行輸出
從檔案中讀取輸入
read
也接收從檔案的輸入,可以使用檔案重定向,或者管道的方式
使用檔案重定向的方式
示例:
[[email protected] read]# cat test_4.sh #!/bin/bash exec 0< test_1.sh//重定向,將輸入重定向到test_1.sh count=1//記錄行數 while read line//line是變數名 do echo "#$count: $line"//輸出行數,和檔案該行的內容 count=$[ $count + 1 ] done [[email protected] read]# ls test_1.sh test_2.sh test_3.sh test_4.sh [[email protected] read]# bash test_4.sh //執行結果 #1: #!/bin/bash #2: #3: echo "type your input" #4: read input #5: echo "you type $input"
使用管道的方式:<