說(shuō)明:本文部分內(nèi)容均摘取自書(shū)籍《Linux命令行與shell腳本編程大全》,版權(quán)歸原作者所有?!禠inux命令行與shell腳本編程大全》(第三版)第十四章學(xué)習(xí)總結(jié)
第十四章:處理用戶(hù)輸入
本章內(nèi)容
傳遞參數(shù)
跟蹤參數(shù)
移動(dòng)變量
處理選項(xiàng)
將選項(xiàng)標(biāo)準(zhǔn)化
獲取用戶(hù)輸入
14.1 命令行參數(shù)
14.1.1 讀取參數(shù)
bash shell會(huì)將一些稱(chēng)為位置參數(shù)的特殊變量分配給輸入到命令行中的所有參數(shù)。
位置參數(shù)變量是標(biāo)準(zhǔn)的數(shù)字
$0是程序名
$1是第一個(gè)參數(shù)
$2是第二個(gè)參數(shù)
依次類(lèi)推,知道第九個(gè)參數(shù)$9
編寫(xiě)test1.sh腳本
#!/bin/bash
factorial=1
for (( number=1;number<=$1;number++ ))
do
factorial=$[ $factorial * $number ]
done
echo The factorial of $1 is $factorial
執(zhí)行命令
./test1.sh 5
編寫(xiě)test2.sh腳本
#!/bin/bash
total=$[ $1 * $2 ]
echo The first paramter is $1.
echo The second paramter is $2.
echo Thetotal paramter is $total.
執(zhí)行命令
./test2.sh 2 5
編寫(xiě)test3.sh腳本
#!/bin/bash
echo Hello $1,glad to meet you.
執(zhí)行命令
./test3.sh 'Rich Blum'
如果腳本需要的命令行參超過(guò)9個(gè)時(shí),使用${10}形式獲取
編寫(xiě)test4.sh腳本
#!/bin/bash
total=$[ ${10} * ${11} ]
echo The tenth parameter is ${10}
echo The eleventh parameter is ${11}
echo The total is $total
執(zhí)行命令
./test4.sh 1 2 3 4 5 6 7 8 9 10 11 12
14.1.2 讀取腳本名
使用$0參數(shù)獲取shell在命令行啟動(dòng)的腳本名
編寫(xiě)test5.sh腳本
#!/bin/bash
echo The zero parameter is set to:$0
執(zhí)行命令
bash test5.sh
使用basename命令獲取不包含路徑的腳本名
編寫(xiě)test5b.sh
#!/bin/bash
name=$(basename $0)
echo
echo The script name is:$name
使用這種方法來(lái)編寫(xiě)基于腳本名執(zhí)行不同功能的腳本
編寫(xiě)test6.sh腳本
#!/bin/bash
name=$(basename $0)
if [ $name = "addem" ]
then
total=$[ $1 + $2 ]
elif [ $name = "multem" ]
then
total=$[ $1 * $2 ]
fi
echo
echo The calculated value is $total
執(zhí)行命令
cp test6.sh addem
cp test6.sh multem
./addem 2 5
./multem 2 5
14.1.3 測(cè)試參數(shù)
腳本在使用參數(shù)前,需要檢查其中是否存在數(shù)據(jù)
編寫(xiě)test7.sh腳本
#!/bin/bash
if [ -n "$1" ]
then
echo Hello $1,glad to meet you.
else
echo "Sorry,you did not identify yourself."
fi
執(zhí)行命令
./test7.sh Rich
./test7.sh
14.2 特殊參數(shù)變量
14.2.1 參數(shù)統(tǒng)計(jì)
特殊變量$#含有腳本運(yùn)行時(shí)攜帶的命令行參數(shù)的個(gè)數(shù)
編寫(xiě)test8.sh腳本
#!/bin/bash
echo There were $# parameters supplied.
執(zhí)行命令
./test8.sh
./test8.sh 1 2 3 4 5
./test8.sh "Rich Blum"
編寫(xiě)test9.sh腳本
#!/bin/bash
if [ $# -ne 2 ]
then
echo
echo Usage:test9.sh a b
echo
else
total=$[ $1 + $2 ]
echo
echo The total is $total
echo
fi
執(zhí)行命令
./test9.sh
./test9.sh 10
./test9.sh 10 15
獲取最后一個(gè)命令行參數(shù)變量
編寫(xiě)test10.sh腳本
#!/bin/bash
params=$#
echo
echo The total parameter is $params
echo The last parameter is ${!#}
echo
執(zhí)行命令
./test10.sh
./test10.sh 1 2 3
./test10.sh 1 2 3 4
14.2.2 抓取所有的數(shù)據(jù)
使用$*和$@變量來(lái)訪問(wèn)所有的參數(shù)
使用for命令遍歷這兩個(gè)變量時(shí)
$*變量會(huì)將所有參數(shù)當(dāng)成單個(gè)參數(shù)
$@變量會(huì)單獨(dú)處理每個(gè)參數(shù)
編寫(xiě)test11.sh腳本
#!/bin/bash
echo
echo "Using the \$* method:$*"
echo "Using the \$@ method:$@"
echo
執(zhí)行命令
./test11.sh rich barbara katie jseeica
編寫(xiě)test12.sh腳本
#!/bin/bash
echo
count=1
for param in "$*"
do
echo "\$* parameter #Scount = $param"
count=$[ $count + 1 ]
done
echo
count=1
for param in "$@"
do
echo "\$@ parameter #Scount = $param"
count=$[ $count + 1 ]
done
執(zhí)行命令
./test12.sh rich barbara katie jseeica
14.3 移動(dòng)變量
shift命令會(huì)根據(jù)所在的相對(duì)位置來(lái)移動(dòng)命令行參數(shù)
敲門(mén):使用shift命令的時(shí)候要小心。如果某個(gè)參數(shù)被移除,它的值就被丟棄了,無(wú)法再恢復(fù)
編寫(xiě)test13.sh腳本
#!/bin/bash
echo
count=1
while [ -n "$1" ]
do
echo "Parameter #$count = $1"
count=$[ $count+1 ]
shift
done
執(zhí)行命令
./test13.sh rich barbara katie jessica
編寫(xiě)test14.sh腳本
#!/bin/bash
echo
echo "The original parameters: $*"
shift 2
echo "Here's the new first parameter: $1"
執(zhí)行命令
./test14.sh 1 2 3 4 5
14.4 處理選項(xiàng)
14.4.1 查找選項(xiàng)
1.處理簡(jiǎn)單選項(xiàng)
在提取每個(gè)單獨(dú)參數(shù)時(shí),用case語(yǔ)句來(lái)判斷某個(gè)參數(shù)是否為選項(xiàng)
編寫(xiě)test15.sh腳本
#!/bin/bash
echo
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 "Found the an option" ;;
esac
shift
done
執(zhí)行命令
./test15.sh -a -b -c -d
2.分離參數(shù)和選項(xiàng)
Linux通過(guò)雙破折線(--)來(lái)區(qū)分選項(xiàng)和參數(shù)
編寫(xiě)test16.sh腳本
#!/bin/bash
echo
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" ;;
--) shift
break ;;
*) echo "$1 is not an option" ;;
esac
shift
done
#
count=1
for param in $@
do
echo "Parameter #count:$param"
count=$[ $count+1 ]
done
執(zhí)行命令
./test16.sh -a -b -c test1 test2 test3
./test16.sh -a -b -c -- test1 test2 test3
3.處理帶值的選項(xiàng)
有些選項(xiàng)會(huì)帶上一個(gè)額外的參數(shù)值,腳本必須能夠檢測(cè)到并正確處理
編寫(xiě)test17.sh腳本
#!/bin/bash
echo
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 ;;
-c) echo "Found the -c option" ;;
--)
shift
break ;;
*) echo "$1 is not an option";;
esac
shift
done
#
count=1
for param in $@
do
echo "Parameter #$count:$param"
count=$[ $count+1 ]
done
執(zhí)行命令
./test17.sh -a -b test1 -d
./test17.sh -b test1 -a -d
14.4.2 使用getopt命令
getopt命令是一個(gè)在處理命令選項(xiàng)和參數(shù)時(shí)非常方便的工具。它能夠識(shí)別命令行參數(shù),從而在腳本中解析它們時(shí)更方便。
1.命令的格式
命令格式:getopt optstring parameters
命令說(shuō)明:getopt命令可以接受一系列任意形式的命令行選項(xiàng)和參數(shù)
敲門(mén):getopt命令有一個(gè)更高級(jí)的版本叫做getopts(注意這是復(fù)數(shù)形式)。getopts命令會(huì)在本章隨后部分降到。因?yàn)檫@兩個(gè)命令的拼寫(xiě)幾乎一摸一樣,所以很容易混淆,一定要小心。
命令演示:getopt ab:cd -a -b test1 -cd test2 test3
演示結(jié)果:-a -b test1 -c -d – test2 test3
演示說(shuō)明:optstring定義了四個(gè)有效選項(xiàng)字母:a,b,c和d。冒號(hào)(:)被放在了字母b后面,因?yàn)閎選項(xiàng)需要一個(gè)參數(shù)值。當(dāng)getopt命令運(yùn)行時(shí),它會(huì)檢查提供的參數(shù)列表(-a -b test1 -c -d – test2 test3),并基于提供的optstring進(jìn)行解析。注意,它會(huì)自動(dòng)將-cd選項(xiàng)分成兩個(gè)單獨(dú)的選項(xiàng),并插入雙破折線來(lái)分割行中的額外參數(shù)。
getopt說(shuō)明
如果指定了一個(gè)不在optstring中的選項(xiàng),getopt命令會(huì)產(chǎn)生一條錯(cuò)誤的消息
如果想忽略這條錯(cuò)誤消息,可以在命令后加-q選項(xiàng)
getopt命令選項(xiàng)必須出現(xiàn)在optstring之前
getopt命令并不擅長(zhǎng)處理帶空格和引號(hào)的參數(shù)值
2.在腳本中使用getopt
編寫(xiě)test18.sh腳本
#!/bin/bash
#
set -- $(getopt -q ab:cd "$@")
#
echo
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 ;;
-c) echo "Found the -c option" ;;
-d) echo "Found the -d option" ;;
--) shift
break ;;
*) echo "$1 is not an option" ;;
esac
shift
done
#
count=1
for param in "$@"
do
echo "Parameter #$count:$param"
count=$[ $count+1 ]
done
執(zhí)行命令
./test18.sh -ac
./test18.sh -a -b test1 -cd test2 test3 test4
14.4.3 使用更高級(jí)的getopts
getopts命令(注意是復(fù)數(shù))內(nèi)建于bash shell。
命令格式:getopts optstring variable
命令說(shuō)明: optstring與 getopt命令中的optstring相同
使用OPTARG環(huán)境變量獲取選項(xiàng)的參數(shù)值
編寫(xiě)test19.sh腳本
#!/bin/bash
echo
while getopts :ab:c opt
do
case "$opt" in
a) echo "Found the -a option" ;;
b) echo "Found the -b option, with value $OPTARG" ;;
c) echo "Found the -c option" ;;
*) echo "Unknown option: $opt" ;;
esac
done
執(zhí)行命令
./test19.sh -ab test1 -c
./test19.sh -b "test1 test2" -a
./test19.sh -abtest1
./test19.sh -acde
使用shift命令和OPTIND值來(lái)移動(dòng)參數(shù)
編寫(xiě)test20.sh腳本
#!/bin/bash
echo
while getopts :ab:cd opt
do
case "$opt" in
a) echo "Found the -a option" ;;
b) echo "Found the -b option, with value $OPTARG" ;;
c) echo "Found the -c option" ;;
d) echo "Found the -d option" ;;
*) echo "Unknown option: $opt" ;;
esac
done
#
shift $[ $OPTIND - 1 ]
#
echo
count=1
for param in "$@"
do
echo "Parameter $count: $param"
count=$[ $count+1 ]
done
執(zhí)行命令
./test20.sh -a -b test1 -d test2 test3 test4
14.5 將選項(xiàng)標(biāo)準(zhǔn)化
在創(chuàng)建shell腳本時(shí),可以決定使用哪些字母以及它們的用法
但有些字母選項(xiàng)在linux世界里已經(jīng)擁有了某種程度的標(biāo)準(zhǔn)含義
常用的Linux命令選項(xiàng)
選項(xiàng):描述
-a:顯示所有對(duì)象
-c:生成一個(gè)計(jì)數(shù)
-d:指定一個(gè)目錄
-e:擴(kuò)展一個(gè)對(duì)象
-f:指定讀入數(shù)據(jù)的文件
-h:顯示命令的幫助信息
-i:忽略文本大小寫(xiě)
-l:產(chǎn)生輸出的長(zhǎng)格式版本
-n:使用非交互模式(批處理)
-o:將所有輸出重定向到指定的輸出文件
-q:以安靜模式運(yùn)行
-r:遞歸地處理目錄和文件
-s:以安靜模式運(yùn)行
-v:生成詳細(xì)輸出
-x:排除某個(gè)對(duì)象
-y:對(duì)所有問(wèn)題回答yes
14.6 獲得用戶(hù)輸入
14.6.1 基本的讀取
read命令從標(biāo)準(zhǔn)輸入(鍵盤(pán))或另一個(gè)文件描述符中接受輸入。
編寫(xiě)test21.sh腳本
#!/bin/bash
echo -n "Enter your name:"
read name
echo "Hello $name,welcome to my program."
編寫(xiě)test22.sh腳本
#!/bin/bash
read -p "Please enter your age:" age
days=$[ $age * 365]
echo "That makes you over $days days old!"
編寫(xiě)test23.sh腳本
#!/bin/bash
read -p "Enter your name:" first last
echo "Checking data for $last, $first..."
read命令會(huì)將它收到的任何數(shù)據(jù)都放進(jìn)特殊環(huán)境變量REPLY中
編寫(xiě)test24.sh腳本
#!/bin/bash
read -p "Enter your name:"
echo
echo Hello $REPLY, welcome to my program.
14.6.2 超時(shí)
使用read命令時(shí),可以使用-t選項(xiàng)指定read命令等待輸入的秒數(shù)。當(dāng)計(jì)數(shù)器過(guò)期后,read命令返回一個(gè)非零退出狀態(tài)碼
編寫(xiě)test25.sh
#!/bin/bash
if read -t 5 -p "Please enter your name:" name
then
echo "Hello $name,welcome to my script"
else
echo
echo "Sorry,too slow!"
fi
使用read命令-n選項(xiàng)統(tǒng)計(jì)輸入的字符數(shù)。當(dāng)輸入的字符達(dá)到預(yù)設(shè)的字符數(shù)時(shí),就自動(dòng)退出,將輸入的數(shù)據(jù)賦給變量
編寫(xiě)test26.sh腳本
#!/bin/bash
read -n1 -p "Do you want to continue [Y/N]?" answer
case $answer in
Y | y) echo
echo "fine,continue on..." ;;
N | n) echo
echo "OK,goodbay"
exit;;
esac
echo "The is the end of the script"
14.6.3 隱藏方式讀取
使用-s選項(xiàng),隱藏read命令中輸出的數(shù)據(jù),避免直接出現(xiàn)在顯示器上
編寫(xiě)test27.sh命令
#!/bin/bash
read -s -p "Enter your password:" pass
echo
echo "Is your password really $pass?"
14.6.4 從文件中讀取
使用read讀取Linux系統(tǒng)上文件里保存的數(shù)據(jù)。每次調(diào)用read命令時(shí),它都會(huì)從文件中讀取一行數(shù)據(jù)。當(dāng)文件中沒(méi)有內(nèi)容時(shí),read命令退出并返回非零退出狀態(tài)碼
編寫(xiě)test文本
One
Two
Three
編寫(xiě)test28.sh腳本
#!/bin/bash
count=1
cat test | while read line
do
echo "line $count: $line"
count=$[ $count+1 ]
done
echo "Finished processing the file"
14.7 小結(jié)
本章講述了3種不同的方法來(lái)從腳本用戶(hù)處理獲得數(shù)據(jù)。命令行參數(shù)允許用戶(hù)運(yùn)行腳本時(shí)直接從命令行輸入數(shù)據(jù)。腳本通過(guò)位置參數(shù)來(lái)取回命令行參數(shù)并將它們賦給變量