天天看點

【讀書筆記】Linux指令行與Shell腳本程式設計大全--處理使用者輸入1. 指令行參數2.特殊參數變量3.移動變量–shift指令[周遊指令行參數的另一個好方法]4.處理選項5.将選項标準化6.獲得使用者輸入–read

文章目錄

  • 1. 指令行參數
    • 1.1 讀取參數
    • 1.2 讀取腳本名--`$0`
    • 1.3 測試參數--`-n`
  • 2.特殊參數變量
    • 2.1 參數統計--`$#`
    • 2.2 抓取所有資料--`$*`和`[email protected]`[周遊指令行的絕妙方法]
  • 3.移動變量--shift指令[周遊指令行參數的另一個好方法]
  • 4.處理選項
    • 4.1 查找選項
    • 4.2 使用getopt指令-格式化指令行選項和參數
    • 4.3 使用更進階的getopts--避開getopt指令的劣勢擴充了一些功能
  • 5.将選項标準化
  • 6.獲得使用者輸入--`read`
    • 6.1 基本的擷取
    • 6.2 逾時--read需要逾時判斷
    • 6.3 隐藏方式讀取--`-s`典型應用于密碼輸入上
    • 6.4 從檔案讀取

1. 指令行參數

1.1 讀取參數

bash shell會将一些稱為位置參數(positional parameter)的特殊變量配置設定給輸入到指令行中的所有參數(包括shell所執行的腳本名稱)。

位置參數變量是标準的數字:

$0

是程式名,

$1

是第一個參數,通常依次到

$9

eg:

a=1
for((num=1;num<$1;num++))
do
        a=$[ $a+$num ]
done
echo $a
#11
           

notice:

  1. 需要輸入更多的指令行參數,則每個參數都必須用空格分開。
  2. shell腳本會自動将指令行參數的值配置設定給變量,不需要作任何處理。
  3. 當遇到傳入參數帶有空格時,記得用引号包括起來(單雙引号都可)。
  4. 當指令行參數超過9個時候,第10個參數以及第10+n個參數的引用需要使用花括号。如

    ${10}

1.2 讀取腳本名–

$0

以用$0參數擷取shell在指令行啟動的腳本名。

讀取腳本名有如下需要注意的:

  1. 如果使用另一個指令來運作shell腳本,指令會和腳本名混在一起,出現在$0參數中。
  2. 當傳給$0變量的實際字元串不僅僅是腳本名,而是完整的腳本路徑時,變量$0就會使用整個路徑。

Q:如何避免上述問題?

A:使用

basename

指令即可。

eg:

echo $0
path=$(basename $0)
echo $path

#/home/hogoadr/workspace/share/george/shell/myshell
#myshell
           

1.3 測試參數–

-n

當腳本認為參數變量中會有資料而實際上并沒有時,腳本很有可能會産生錯誤消息。

在使用參數前一定要檢查其中是否存在資料。

可以使用**-n**測試來檢查指令行參數$1中是否有資料。

eg:

if [ -n "$1" ]					#使用 -n 測試 是否執行使用參數1的相關代碼塊
then
a=1
for((num=1;num<$1;num++))
do
        a=$[ $a+$num ]
done
echo $a
else
        echo "no parameter 1 "
fi

#no parameter 1
           

2.特殊參數變量

2.1 參數統計–

$#

特殊變量$#含有腳本運作時攜帶的指令行參數的個數。可以在腳本中任何地方使用這個特殊變量,就跟普通變量一樣。這樣就可以避免多個參數需要一個一個測試的繁瑣。

eg:

if [ $# -eq 2 ];then
        echo "parameter is 2"
elif [ $# -eq 1 ];then
        if [ -n "$1" ];then
                a=1
                for((num=1;num<$1;num++))
                do
                        a=$[ $a+$num ]
                done
                echo $a
        fi
else
        echo "no parameter 1 "
fi

#根據攜帶參數走不同分支
           

notice:

  1. if-then語句用**-ne**測試指令行參數數量。如果參數數量不對,會顯示一條錯誤消息告知腳本的正确用法。
  2. ${!#}

    用來擷取指令行中最後一個參數。
  3. 當指令行上沒有任何參數時,

    $#

    的值為0,params變量的值也一樣,但${!#}變量會傳回指令行用到的腳本名。

2.2 抓取所有資料–

$*

[email protected]

[周遊指令行的絕妙方法]

指令 描述
$* 用來輕松通路所有的參數

1.将指令行上提供的所有參數

當作一個單詞儲存

2.基本上$*變量會将這些參數視為一個整體

而不是多個個體

能夠在單個變量中存儲所有的指令行參數
[email protected] 用來輕松通路所有的參數 将指令行上提供的所有參數當作同一字元串中的多個獨立的單詞,通常使用for指令周遊得到每個參數值

eg:

cnt=1
for para in $"$*"
do
	echo "\$* $cnt = $para"
	cnt=$[ $cnt + 1 ]
done

cnt=1
for para in $"[email protected]"
do
	echo "\[email protected] $cnt = $para"
	cnt=$[ $cnt + 1 ]
done

#$* 1 = 5:8:6:9:7
#[email protected] 1 = 5
#[email protected] 2 = 8
#[email protected] 3 = 6
#[email protected] 4 = 9
#[email protected] 5 = 7
           

3.移動變量–shift指令[周遊指令行參數的另一個好方法]

shift指令會根據它們的相對位置來移動指令行參數。(周遊指令行參數的另一個好方法,在不知道有多少個指令行參數的時候,隻讀第一個參數)

notice:

  1. 在使用shift指令時,預設情況下它會将每個參數變量向左移動一個位置。
  2. 使用shift指令的時候要小心。如果某個參數被移出,它的值就被丢棄了,無法再恢複。
  3. 可以一次性移動多個位置,即給shift 指令後面跟個n個位置參數,指明要移動的位置數。
  4. 通過使用shift指令的參數,可以輕松的跳過不需要的參數。

eg:

echo 
count=1 
while [ -n "$1" ] 
do 
 echo "Parameter #$count = $1" 			#不知道實際參數個數,隻取第一個參數
 count=$[ $count + 1 ] 
 shift 
done

#Parameter #1 = 5
#Parameter #2 = 8
#Parameter #3 = 6
#Parameter #4 = 9
#Parameter #5 = 7
           

4.處理選項

4.1 查找選項

bash shell 腳本可以像處理指令行參數一樣處理指令行選項。

處理指令行選項需要注意如下兩點:

  1. 分離參數和選項;
  2. 處理帶值的選項。

Q:如何分離參數和選項?

A:Linux使用标準方法是使用特殊字元。雙破折線(–),shell會用雙破折現線來表明選項清單的結束。

ps:處理帶值的選項通常包括注意選項的合并。eg:

ls -la

4.2 使用getopt指令-格式化指令行選項和參數

getopt指令可以接受一系列任意形式的指令行選項和參數,并自動将它們轉換成适當的格式,是一個在處理指令行選項和參數時非常友善的工具。

其格式如下:

getopt optstring parameters
           

optstring是這個過程的關鍵所在。

它定義了指令行有效的選項字母,還定義了哪些選項字母需要參數值。

其流程如下:

首先,在optstring中列出你要在腳本中用到的每個指令行選項字母。

然後,在每個需要參數值的選項字母後加一個冒号。

getopt指令會基于你定義的optstring解析提供的參數。

eg:

$ getopt ab:cd -a -b test1 -cd test2 test3
 -a -b test1 -c -d -- test2 test3
           

ps: getopt -q 選項可以忽略錯誤資訊(若指定了一個不在optstring中的選項)

Q:如何在腳本中使用getopt指令?

A:方法是用getopt指令生成的格式化後的版本來替換已有的指令行選項和參數。用set指令能夠做到。

set指令的選項之一是雙破折線(–),它會将指令行參數替換成set指令的指令行值。

該方法會将原始腳本的指令行參數傳給getopt指令,之後再将getopt指令的輸出傳給set指令,用getopt格式化後的指令行參數來替換原始的指令行參數。

其格式如下:

現在原始的指令行參數的值會被getopt指令的輸出替換,而getopt指令以及将原始指令行參數進行了格式化。

notice:

getopt指令并不擅長處理帶空格和引号的參數值。它會将空格當作參數分隔符,而不是根據雙引号将二者當作一個參數。

4.3 使用更進階的getopts–避開getopt指令的劣勢擴充了一些功能

getopts指令(注意是複數)是bash shell的内建。相比getopt指令多了一些擴充功能并且避開了getopt指令不擅長處理帶空格和引号的參數值。

指令 差別
getopt 1.将指令行上選項和參數處理後隻生成一個輸出
getopts

1.能夠和已有的shell參數變量配合默契

2.一次隻處理指令行上檢測到的一個參數

3.處理完所有參數後,退出并傳回一個大于0的退出狀态碼

4.可以在參數值中包含空格

5.可以将選項字母和參數值放在一起使用而不用加空格

6.能夠将指令行上未定義的選項統一輸出成問号

getopts指令格式如下:

getopts optstring variable
           

notice:

  1. optstring同樣和getopt一樣也是關鍵;
  2. 有效的選項字母都會列在optstring中,如果選項字母要求有參數值,就加一個冒号;
  3. 要去掉錯誤消息,可以在optstring之前加一個冒号,這和getopt指令顯得不同;
  4. getopts指令将目前參數儲存在variable中;
  5. getops指令解析指令行選項時會移除開頭的單破折線。

ps:

1.getopts指令會用到兩個環境變量。(OPTARG和OPTIND)

OPTARG環境變量會儲存選項需要跟的參數值;

OPTIND環境變量儲存了參數清單中getopts指令正在處理的參數位置。(getopts指令在處理每個選項時,OPTIND的值會增一)

5.将選項标準化

【讀書筆記】Linux指令行與Shell腳本程式設計大全--處理使用者輸入1. 指令行參數2.特殊參數變量3.移動變量–shift指令[周遊指令行參數的另一個好方法]4.處理選項5.将選項标準化6.獲得使用者輸入–read

6.獲得使用者輸入–

read

6.1 基本的擷取

read指令從标準輸入(鍵盤)或另一個檔案描述符中接收輸入。

ps:

  1. echo -n 選項 不會在字元串末尾輸出換行符。
  2. read指令使用-p選項,允許直接在read指令行指定提示符。(若使用了-p選項而沒有指定提示符,則會出乎所料哦)。
  3. read指令會将提示符輸入的所有資料配置設定給單個變量(若變量數量不夠,剩下的資料就全部配置設定給最後一個變量,是以要麼指定多個變量,要麼全部配置設定給最後一個變量)。
  4. 若read指令行中沒有指定變量,則read指令會将它收到的任何資料都放進特殊環境變量REPLY中。

eg:

read -p name
echo $name
read name
echo $name
read -p "Please input you namef: " namef
echo $namef 
read -p "Please input you namef: " names
echo $names
read
echo $REPLY

#namewang heng
#
#wang heng
#wang heng
#Please input you namef: wang
#wang
#Please input you namef: heng
#heng
#who
#who
           

6.2 逾時–read需要逾時判斷

Q:如何做到read逾時判斷?

A:有如下兩種辦法:

  1. read -t 計時判斷。-t選項指定一個計時器,指定了read指令等待輸入的秒數,當計時器過期後,read指令會傳回一個非零的退出狀态碼。
  2. 也可以讓read指令來統計輸入的字元數(-n)。當輸入的字元達到預設的字元數時,則自動退出,将輸入指派給變量。

eg:

#read -t
if read -t 5 -p "Please input a num: " num;then
        echo "the num is $num"
else
        echo "is too slow"
fi

#read -n
read -n1 -p "Continue?[Y/N]" answer		#将-n選項和值1一起使用,告訴read指令在接受單個字元後退出
case $answer in
Y | y)  echo "continue..";;
N | n)  echo
        echo "not continue.."
        exit;;
esac
echo "shell is over.."

#Please input a num: 2
#the num is 2
#Continue?[Y/N]n
#not continue..

#Please input a num: is too slow
#Continue?[Y/N]ycontinue..
#shell is over..
           

6.3 隐藏方式讀取–

-s

典型應用于密碼輸入上

-s選項可以避免在read指令中輸入的資料出現在顯示器上(實際上,資料會被顯示,隻是read指令會将文本顔色設成跟背景色一樣)

eg:

#read -s
if read -t 5 -s -p "Please input the passwd: " pswd;then
        echo "the pswd is $pswd"
else
        echo "is too slow"
fi

#Please input the passwd: the pswd is 123
           

6.4 從檔案讀取

每次調用read指令,它都會從檔案中讀取一行文本。

當檔案中再沒有内容時,read指令會退出并傳回非零退出狀态碼。

Q:如何将檔案内容傳輸給read指令?

A:最常見的方法是對檔案使用cat指令,将結果通過管道直接傳給含有read指令的while指令。

eg:

cnt=1
cat 3_1_while.log | while read line
do
	echo "read line$cnt is $line"
	cnt=$[ $cnt + 1 ]
done

#read line1 is 5
#read line2 is 4
#read line3 is 3
#read line4 is 2
#read line5 is 1
           

申明:文中沒特殊注明,圖皆來自Linux指令行與shell腳本程式設計大全<第三版>。

繼續閱讀