歡迎您光臨本站 註冊首頁

bash shell筆記4 處理用戶輸入

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0

知識體系:
#使用命令行參數
#設置選項
#獲取用戶輸入
有時編寫的腳本需要能和運行腳本的人員進行交互,bash shell提供了一些方法來從用戶處獲取數據,這些方法有如下三種:
1- 命令行參數(添加在命令后的參數)
2- 命令行選項(修改命令行為的單字元串)
3- 直接讀取鍵盤輸入

1、命令行參數
向shell腳本傳遞數據最基本的方式就是命令行參數,主要就是說通過一些特殊變數是的bash shell自動把輸入的參數賦值給變數才執行腳本.這些變數叫做位置參數,分別有$1為第一個參數、$2為第二個參數、$0為程序名稱...
1.1、讀取參數
如下看個例子就能理解這個位置參數的概念了:
[root@wzp ~]# chmod u x 1.1test
[root@wzp ~]# cat 1.1test
#!/bin/bash
a=1
for (( b=1; b<=$1; b ))
do
a=$[ $a * $b ]
done
echo the factorial of $1 is $a
[root@wzp ~]# ./1.1test 5
the factorial of 5 is 120
[root@wzp ~]# ./1.1test 4
the factorial of 4 is 24
主要來看./xx後面附帶的命令行參數,只有一個參數也即為第一個參數很明顯賦值為$1,通過for循環計算出累乘結果,所以你輸入的第一個參數值改變了,結果也就隨著改變.
如果要輸入更多的命令行參數,那麼每個命令行參數必須使用空格分隔出來,下面看一個例子:
[root@wzp ~]# cat 1.1test
#!/bin/bash
total=$[ $1 * $2 ]
echo the first param is $1
echo the second param is $2
echo the total value is $total
[root@wzp ~]# ./1.1test 2 3
the first param is 2


the second param is 3
the total value is 6
[root@wzp ~]# ./1.1test 4 7
the first param is 4
the second param is 7
the total value is 28
如上腳本很容易理解,我們看到2/3和4/7都分別被賦值給$1和$2,這裡就是通過命令行參數之間的空格分開實現的.當然,數值可以給賦值,對於文本字元串也是可以的,如果要將出現空格的連於一體的參數值可以通過單引號或者雙引號括起來,這樣bash shell就將其視為一個參數值,先來看個例子:
[root@wzp ~]# cat 1.1test
#!/bin/bash
echo hello $1,glad to meet you.
[root@wzp ~]# ./1.1test 51cto gdin
hello 51cto,glad to meet you.
[root@wzp ~]# ./1.1test 'netease corporation'
hello netease corporation,glad to meet you.
對於腳本中沒有附帶$2變數則把gdin參數忽略了.
還有一點必須說明的:
如果腳本輸入的命令參數多於9個,就必須使用大括弧把變數括起來,如{10},來看個例子:
[root@wzp ~]# cat 1.1test
#!/bin/bash
total=$[ ${10} ${11} ]
echo the tenth param is ${10}
echo the eleventh param is ${11}
echo the total is $total
[root@wzp ~]# ./1.1test 1 2 3 4 5 6 7 8 9 10 11
the tenth param is 10
the eleventh param is 11
the total is 21
對於這樣的結果很好理解,只要注意下{10 }這個東東就行了!
1.2、讀取程序名稱
一開始我就在上面提到程序名稱用$0即可表示,Ok,先看個例子:
[root@wzp ~]# chmod u x 1.2test
[root@wzp ~]# cat 1.2test
#!/bin/bash
echo the name of the program is:$0
[root@wzp ~]# ./1.2test
the name of the program is:./1.2test
[root@wzp ~]# /root/1.2test


the name of the program is:/root/1.2test
很明顯,得出的結果不是我們要的,我們只要輸出1.2test這個結果.它所傳遞的變數$0的字元串是程序的完整路徑,而不是名稱,這裡我們可以通過basename命令實現只返回程序名稱,把腳本修改成如下:
[root@wzp ~]# cat 1.2test
#!/bin/bash
name=`basename $0`
echo the name of the program is:$name
[root@wzp ~]# ./1.2test
the name of the program is:1.2test
[root@wzp ~]# $HOME/1.2test
the name of the program is:1.2test
呵呵,這下通過basename實現我們要的結果,有點注意的是使用反單引號來給name賦值,否則命令無法生效!
通過基於使用腳本的名稱可以實現執行不同功能,下面看個例子:
[root@wzp ~]# cp 1.2test 51cto
[root@wzp ~]# ln -s 1.2test netease
[root@wzp ~]# ls -l 1.2test 51cto netease
-rwxr--r-- 1 root root 179 02-13 11:21 1.2test
-rwxr--r-- 1 root root 179 02-13 11:22 51cto
lrwxrwxrwx 1 root root 7 02-13 11:22 netease -> 1.2test
[root@wzp ~]# cat 1.2test
#!/bin/bash
name=`basename $0`
if [ $name = "51cto" ]
then
echo $name is a great IT community
elif [ $name = "netease" ]
then
echo $name is a great internet-sp corparation
fi
[root@wzp ~]# ./51cto
51cto is a great IT community
[root@wzp ~]# ./netease
netease is a great internet-sp corparation
上面的例子通過腳本名稱實現了不同內容的輸出,可知basename好用啦!
腳本是先判斷basename,然後根據basename執行函數.
1.3、測試參數
在shell腳本中使用命令行參數要小心,如果執行腳本缺少必要的參數,則會出現報錯信息,如下:


[root@wzp ~]# cat 1.1test
#!/bin/bash
total=$[ ${10} ${11} ]
echo the tenth param is ${10}
echo the elevnth param is ${11}
echo the total is $total
[root@wzp ~]# ./1.1test
./1.1test: line 2: : syntax error: operand expected (error token is " ")
the tenth param is
the elevnth param is
the total is
我們不輸入任何命令行參數,則腳本無法執行.
所以,我們可以通過-n這個參數進行檢測:
[root@wzp ~]# cat 1.2test
#!/bin/bash
if [ -n "$1" ]
then
echo $1 exists !
else
echo your inputting is wrong
fi
[root@wzp ~]# ./1.2test twentyfour
twentyfour exists !
[root@wzp ~]# ./1.2test
your inputting is wrong
由此可見,通過該方法是檢測參數是否存在的好方法.

2、特殊的參數變數
在bash shell中有一些特殊的變數用戶跟蹤命令行參數.
2.1、參數計數
我們可以使用bash shell提供的特殊變數$#來檢測執行腳本時所包含的命令行參數的個數,看如下例子:
[root@wzp ~]# cat 2.1test
#!/bin/bash
echo there were $# parameters supplied.
[root@wzp ~]# chmod u x 2.1test
[root@wzp ~]# ./2.1test
there were 0 parameters supplied.
[root@wzp ~]# ./2.1test aa bb cc
there were 3 parameters supplied.
所以,$#是一個值得我們記住腦中的好變數!
2.2、獲取所有參數
有時候需要獲取命令行中的參數,並對它們進行迭代.這裡主要通過兩個變數來實現對命令行參數的迭代,分別是:
變數$*和變數$@
變數$*將所有參數視為一個單詞


變數$@將分別對待每個參數
我們看個例子(≧▽≦)/
[root@wzp ~]# chmod u x 2.2test
[root@wzp ~]# cat 2.2test
#!/bin/bash
a=1
for param1 in "$*"
do
echo "$* parameter #$a = $param1"
a=$[ $a 1 ]
done
b=1
for param2 in "$@"
do
echo "$# parameter #$b = $param2"
b=$[ $b 1 ]
done
c=1
for param3 in "$#"
do
echo "the total counts = $param3"
c=$[ $c 1 ]
done
[root@wzp ~]# ./2.2test a b c d e f
$* parameter #1 = a b c d e f
$# parameter #1 = a
$# parameter #2 = b
$# parameter #3 = c
$# parameter #4 = d
$# parameter #5 = e
$# parameter #6 = f
the total counts = 6
通過一個for循環迭代特殊變數,充分體現出$*$@$#三個特殊變數用途!

3、移位
bash shell提供了一個工具叫shift命令,實現改變命令行參數的相對位置
默認將每個參數變數左移一位.即為,$3的值移動給變數$2($n 1->$n),而變數$1則被丟棄,當然,$0這個程序名稱沒變.下面看個例子:
[root@wzp ~]# cat 3test
#!/bin/bash
count=1
while [ -n "$1" ]
do
echo "parameter #$count = $1"
count=$[ $count 1 ]
shift
done
[root@wzp ~]# chmod u x 3test
[root@wzp ~]# ./3test 51cto emc linux rac
parameter #1 = 51cto
parameter #2 = emc
parameter #3 = linux
parameter #4 = rac
每測試一個參數,使用shift命令將參數移前一位,所以通過while循環即可是的每個參數都變成$1被循環下去顯示出來.當然,我們可以指定shift的位數,而不是默認的一位.看如下例子:


[root@wzp ~]# cat 3test
#!/bin/bash
echo "the original parameter : $*"
shift 3
echo "the new shift parameter is : $1"
[root@wzp ~]# ./3test aa bb cc dd ee
the original parameter : aa bb cc dd ee
the new shift parameter is : dd
指定位數為3后,aa bb cc則被忽略了,直接把dd當成$1.

4、處理選項
選項是有破折號引導的單個字母,它更改命令的行為.如下羅列一些標準化選項:
**********************************************
選項 描述
-a 實現所有對象
-c 生成計數
-d 指定目錄
-e 展開對象
-f 指定讀取數據的文件
-h 顯示命令的幫助信息
-i 忽略大小寫
-l 生成長格式的輸出
-n 使用非互動式(批量)模式
-o 指定一個輸出文件來重定向輸出
-q 以quite模式退出
-r 遞歸處理目錄和文件
-s 以silent模式執行
-v 生成verbose模式
-x 排除和拒絕
-y 設置所有提問回答為yes
**********************************************
4.1、處理簡單選項
先來看一個例子:
[root@wzp ~]# cat 4test
#!/bin/bash
while [ -n "$1" ]
do
case "$1" in
-a) echo "the -a option exists";;
-b) echo "the -b option exists";;
-c) echo "the -c option exists";;
*) echo "the '$1' is not an option ";;
esac
shift
done


[root@wzp ~]# ./4test -a -b -c -d -e
the -a option exists
the -b option exists
the -c option exists
the '-d' is not an option
the '-e' is not an option
通過case語句循環判斷各個選項,並且通過shift靈活移動選項變數.
4.2、從參數中分離選項
執行shell腳本經常會遇到使用選項又需要使用參數的情況.在linux中的標準方式是通過特殊字元碼(--,雙破折號)將二者分開,表示說當這個腳本程序發現雙破折號后,就自動把剩餘的命令行視為參數,而不再是選項了,如下看個例子:
[root@wzp ~]# cat 4test
#!/bin/bash
while [ -n "$1" ]
do
case "$1" in
-a) echo "the -a option exists";;
-b) echo "the -b option exists";;
-c) echo "the -c option exists";;
--) shift
break;;
*) echo "the '$1' is not an option ";;
esac
shift
done
count=1
for param in $@
do
echo "parameter #$count:$param"
count=$[ $count 1 ]
done
[root@wzp ~]# ./4test -a -c -f -- -b test
the -a option exists
the -c option exists
the '-f' is not an option
parameter #1:-b
parameter #2:test
如上先通過while循環,把滿足條件的選項顯示出來,不滿足條件的選項也顯示出,並說明 is not an option ,當使用--把剩下的被腳本識別為參數的命令行則通過break跳出循環,並且在shift作用下置位成$1,然後在for循環下逐一顯示出來,表示現實出來的即為參數,而非選項!
如上的腳本得仔細分析,不然很容易出錯.
如果不通過雙破折號隔離,如下的結果也是我們想象之中的:


[root@wzp ~]# ./4test -a -c -f -b test
the -a option exists
the -c option exists
the '-f' is not an option
the -b option exists
the 'test' is not an option
完全是while循環的判斷,沒法跳出來執行for循環.

5、獲取用戶輸入
有時在腳本執行過程中需要詢問一個問題並等待執行腳本的人員應答,bash shell提供的read命令可以實現這一需求.
5.1、基本讀取
read命令接受標準輸入(鍵盤輸入),如下示例:
[root@wzp ~]# chmod u x 5.1test
[root@wzp ~]# cat 5.1test
#!/bin/bash
echo -n "please input your name:"
read name
echo "hello $name, welcome to IT website"
[root@wzp ~]# ./5.1test
please input your name:twentyfour
hello twentyfour, welcome to IT website
通過一個-n選項是的腳本執行輸入不用換行顯示.
如上通過echo顯示結果,實際上可以直接通過read命令在-p選項下直接把輸入的內容附加給後面指定的變數,如下例子,效果跟上面完全一樣:
[root@wzp ~]# cat 5.1test
#!/bin/bash
read -p "please input your name:" name
echo "hello $name, welcome to IT website"
[root@wzp ~]# ./5.1test
please input your name:CCIE
hello CCIE, welcome to IT website
所以,我們更多可以採用這種方法.
如上的兩個方法,我們都是把輸入的值賦給了變數name,實際上我們可以不使用這個變數name.這麼一來,read命令會把輸入的命令賦給一個環境變數REPLY,先來看一個效果:
[root@wzp ~]# read
the content will be sent to $REPLY


[root@wzp ~]# echo $REPLY
the content will be sent to $REPLY
我使用把變數轉義不被識別,在read命令下輸入的內容將被緩存賦給環境變數$REPLY,這下再來看個例子:
[root@wzp ~]# cat 5.1test
#!/bin/bash
read -p "please input your name:"
echo "hello $REPLY, welcome to IT website"
[root@wzp ~]# ./5.1test
please input your name:IBM
hello IBM, welcome to IT website
很明顯,這個例子跟如上的很接近,但是這個腳本沒使用name變數,所以我輸入的IBM被系統賦給了環境變數$REPLY.
5.2、計時
如上我們可以通過read命令實現交互性的操作,但是假如沒有執行腳本的人員操作,腳本則無法自動運行下去.這個時候就可以使用-t選項指定一個計時器,表示等待時間段(單位為秒),如果超過指定的時間,read命令將返回一個非零退出狀態,通過判斷語句則使腳本可以自動跳過運行下去,我們先看一個例子:
[root@wzp ~]# chmod u x 5.2test
[root@wzp ~]# cat 5.2test
#!/bin/bash
if read -t 5 -p "please input your name:"
then
echo "hello $REPLY, welcome to come back here"
else
echo "sorry , you are too slow "
fi
[root@wzp ~]# ./5.2test
please input your name:twentyfour
hello twentyfour, welcome to come back here
[root@wzp ~]# ./5.2test
please input your name:sorry , you are too slow
如上通過-t 5是的輸入超過5秒則跳到else的判斷結果,有點需要注意就是-p必須放置在-t的後面,否則報錯!如上我沒有任何輸入,超過5秒,則腳本返回了sorry , you are too slow的內容.
到這裡還有一個挺經典的-n選項不得不提,除了如上輸入時間計時,read還可以通過添加-n選項計數輸入的字元.等輸入的字元達到預定數目時就自動退出,這裡藉助case看一個例子:


[root@wzp ~]# cat 5.2test
#!/bin/bash
read -n1 -p "do you want to continue [Y/N]?"
case $REPLY in
Y | y) echo
echo "fine ,continue on ..";;
N | n) echo
echo "OK, goodbye...";;
esac
[root@wzp ~]# ./5.2test
do you want to continue [Y/N]?y
fine ,continue on ..
[root@wzp ~]# ./5.2test
do you want to continue [Y/N]?N
OK, goodbye...
如上-n後面是數字1,表示read命令接收到一個字元就退出,所以輸入Y/N后不用回車就馬上執行下去了.這裡出現了兩個echo,主要是是的結果換行顯示,更顯人性化.還有就是通過|符號識別大小寫,也是人性化.
5.3、默讀
有時候需要腳本用戶進行輸入,但輸入的數據不顯示出來,比如像password的輸入.這裡可以借用read命令下的-s選項,是的輸入的數據顏色跟背景顏色一致,實現不顯示數據的效果,看如下例子:
[root@wzp ~]# cat 5.3test
#!/bin/bash
read -s -p "please input your passwd:"
echo your passwd is $REPLY
[root@wzp ~]# chmod u x 5.3test
[root@wzp ~]# ./5.3test
please input your passwd:your passwd is aaa
[root@wzp ~]# ./5.3test
please input your passwd:your passwd is 51cto
哈哈,這不失為一個非常棒的選項.還有,別以為數據顏色跟背景顏色一樣后,你可以通過數據把數據選上而顯示出來,linux命令行下輸入的數據不佔位,壓根無法讓你選上!
5.4、讀取文件
read命令可以讀取linux系統上存儲的文件數據,每調用一次read命令,都會去讀取一行文本(注意,是一行,不是整個文件內容),當read命令讀完的文本內容將以非零狀態退出.借用while命令看一個例子:


[root@wzp ~]# cat 5.4test
#!/bin/bash
count=1
cat 51cto.test | while read line
do
echo "LINE $count : $line"
count=$[ $count 1 ]
done
[root@wzp ~]# cat 51cto.test
aaaaaaaaaa
bbbbbbbbbb
cccccccccc
[root@wzp ~]# ./5.4test
LINE 1 : aaaaaaaaaa
LINE 2 : bbbbbbbbbb
LINE 3 : cccccccccc
這裡的51cto.test跟腳本文件放置同一個目錄,當然就把要讀取的文件以絕對路徑寫入腳本防止腳本讀取不到.while命令使用read不斷循環讀取文件51cto.test中每一行,然後顯示出來,直到read讀取完后以非零狀態退出而結束!

本文出自 「twenty_four」 博客,請務必保留此出處http://twentyfour.blog.51cto.com/945260/521448


[火星人 ] bash shell筆記4 處理用戶輸入已經有689次圍觀

http://coctec.com/docs/linux/show-post-49170.html