1. 程式人生 > >shell指令碼使用者輸入處理——shell程式設計學習_七

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] 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命令

getoptsgetopt的升級版本,使用方法大不相同

示例:

[[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"
  • 使用管道的方式:<