第八章、bash腳本編程(上)

第八章、bash腳本編程(上)


05_02_bash腳本編程之一 變量、變量類型等


shell編程: 腳本編程

 

語言轉換器:編譯器,解釋器

 

編程語言:機器語言、彙編語言、高級語言

 

靜態語言:編譯型語言

         特點:強類型(變量)

                     事先轉換成可執行格式

         包括:C、C++、JAVA、C#

        

動態語言:解釋型語言, on the fly

         特點:弱類型

                   邊解釋邊執行

         包括:PHP、SHELL、python、perl

 

面向過程:Shell, C

面向對象: JAVA, Python, perl, C++

 

變量:內存空間,命名

內存:編址的存儲單元

 

變量類型:事先確定數據的存儲格式和長度

         字符

         數值

                   整型

                   浮點型: 11.23, 1.123*10^1, 0.1123*10^2


存儲日期:         

字符:2013/10/10 -  64bit

數值: 99999 - 24bit,


        布爾:真、假    

        

邏輯:1+1>2

邏輯運算:與、或、非、異或

1: 真

0: 假

 

1 & 0  = 0

0 & 1 = 0

0 & 0 = 0

1 & 1 = 1

 

或:

 

非:

! 真 = 假

! 假 = 真


異或:相異爲1,相同爲0

 

shell: 弱類型編程語言

 

強類型,弱類型的特點:

強:變量在使用前,必須事先聲明,甚至還需要初始化;

弱:變量用時聲明,甚至不區分類型;

 

變量賦值:VAR_NAME=VALUE

 

bash變量類型:

         環境變量

         本地變量(局部變量)

         位置變量

         特殊變量

        

1. 本地變量:<set> VARNAME=VALUE: 作用域爲整個bash進程;set 可以省略

2. 局部變量:local VARNAME=VALUE:作用域爲當前代碼段;

3. 環境變量:作用域爲當前shell進程及其子進程;

                export VARNAME=VALUE

                或 

                VARNAME=VALUE; export VARNAME

                 export:“導出”

                export PATH=$PATH:/usr/local/mypath

 

4. 位置變量:$1, $2, ...

5. 特殊變量:$?: 上一個命令的執行狀態返回值;

 

程序執行,可能有兩類返回值:

         1. 程序執行結果

         2. 程序狀態返回代碼(0-255)

                   0: 正確執行

                   1-255:錯誤執行,1,2,127系統預留;

                  

輸出重定向:

>  覆蓋重定向

>>  追加重定向

2>  錯誤重定向   

2>>錯誤追加重定向

&> 同時重定向

 

/dev/null: 軟件設備, bit bucket,數據黑洞    


撤消變量:

unset VARNAME

 

查看當shell中變量:

set:包括本地變量和環境變量

 

查看當前shell中的環境變量:

printenv

env

export

 

腳本:命令的堆砌,按實際需要,結合命令流程控制機制實現的源程序

 

腳本的特殊標記:

shebang: 魔數

#!/bin/bash

# 註釋行,不執行

        

腳本在執行時會啓動一個子shell進程;

         1. 命令行中啓動的腳本會繼承當前shell環境變量;

         2. 系統自動執行的腳本(非命令行啓動)就需要自我定義需要各環境變量;

        

        

05_03_bash腳本編程之二    條件判斷


練習:寫一個腳本,完成以下任務 - 答案爲addusers.sh

1、添加5個用戶, user1,..., user5

2、每個用戶的密碼同用戶名,而且要求,添加密碼完成後不顯示passwd命令的執行結果信息;

3、每個用戶添加完成後,都要顯示用戶某某已經成功添加;

#!/bin/bash

useradd user1

echo "user1" | passwd --stdin user1 &> /dev/null

echo "Add user1 successfully."

 

條件判斷:

         如果用戶不存在

                   添加用戶,給密碼並顯示添加成功;

         否則

                   顯示如果已經沒在,沒有添加;

 

bash中如何實現條件判斷?

條件測試類型:

         整數測試

         字符測試

         文件測試

 

條件測試的表達式:

         [ expression ] : 中括號和expression之間必須有空格

         ` expression `

         test expression

        

整數比較:

         -eq: 測試兩個整數是否相等;比如 $A -eq $B

         -ne: 測試兩個整數是否不等;不等,爲真;相等,爲假;

         -gt: 測試一個數是否大於另一個數;大於,爲真;否則,爲假;

         -lt: 測試一個數是否小於另一個數;小於,爲真;否則,爲假;

         -ge: 大於或等於

         -le:小於或等於

        

命令的邏輯關係:

         邏輯與: &&

                   第一個條件爲假時,第二條件不用再判斷,最終結果已經有;

                   第一個條件爲真時,第二條件必須得判斷;

         邏輯或: ||

        

如果用戶user6不存在,就添加用戶user6

! id user6 && useradd user6

id user6 || useradd user6

 

如果/etc/inittab文件的行數大於100,就顯示好大的文件;

[ `wc -l /etc/inittab | cut -d' ' -f1` -gt 100 ] && echo "Large file."

 

變量名稱:

         1、只能包含字母、數字和下劃線,並且不能數字開頭;

         2、不應該跟系統中已有的環境變量重名;

         3、最好做到見名知義;

 

如果用戶存在,就顯示用戶已存在;否則,就添加此用戶;

id user1 && echo "user1 exists." || useradd user1

 

如果用戶不存在,就添加;否則,顯示其已經存在;

! id user1 && useradd user1 || echo "user1 exists."

 

如果用戶不存在,添加並且給密碼;否則,顯示其已經存在;

! id user1 && useradd user1 && echo "user1" | passwd --stdin user1|| echo "user1 exists."

 

 

練習,寫一個腳本,完成以下要求: - 答案爲adduser2.sh文件

1、添加3個用戶user1, user2, user3;但要先判斷用戶是否存在,不存在而後再添加;

2、添加完成後,顯示一共添加了幾個用戶;當然,不能包括因爲事先存在而沒有添加的;

3、最後顯示當前系統上共有多少個用戶;


 

練習,寫一個腳本,完成以下要求: - 答案爲third.sh文件 

給定一個用戶:

         1、如果其UID爲0,就顯示此爲管理員;

         2、否則,就顯示其爲普通用戶;


使用if語句:

如果 UID爲0;那麼

  顯示爲管理員

否則

  顯示爲普通用戶

 

NAME=user16

USERID=`id -u $NAME`

if [ $USERID -eq 0 ]; then

  echo "Admin"

else

  echo "common user."

fi

 

NAME=user16

if [ `id -u $NAME` -eq 0 ]; then

  echo "Admin"

else

  echo "common user."

fi

 



05_04_bash腳本編程之三 條件判斷及算術運算


1. 練習:寫一個腳本  - 答案爲 bash.sh

判斷當前系統上是否有用戶的默認shellbash

   如果有,就顯示有多少個這類用戶;否則,就顯示沒有這類用戶;

grep "bash$" /etc/passwd &> /dev/null

RETVAL=$?

if [ $RETVAL -eq 0 ]; then

  

if grep "bash$" /etc/passwd &> /dev/null; then

        

提示:“引用”一個命令的執行結果,要使用命令引用;比如: RESAULTS=`wc -l /etc/passwd | cut -d: -f1`

      使用一個命令的執行狀態結果,要直接執行此命令,一定不能引用;比如: if id user1一句中的id命令就一定不能加引號;

           如果想把一個命令的執行結果賦值給某變量,要使用命令引用,比如USERID=`id -u user1`;

      如果想把一個命令的執行狀態結果保存下來,並作爲命令執行成功與否的判斷條件,則需要先執行此命令,而後引用其狀態結果,如

                   id -u user1

                   RETVAL=$?

                   此句絕對不可以寫爲RETVAL=`id -u user1`

        

        

2. 練習:寫一個腳本  - 答案爲bash2.sh

判斷當前系統上是否有用戶的默認shellbash

   如果有,就顯示其中一個的用戶名;否則,就顯示沒有這類用戶;

 

3. 練習:寫一個腳本

給定一個文件,比如/etc/inittab

判斷這個文件中是否有空白行;

如果有,則顯示其空白行數;否則,顯示沒有空白行。

                                      

#!/bin/bash
FILE=/etc/inittab
if [ ! -e $FILE ]; then
  echo "No $FILE."
  exit 8
fi
 
if grep "^$" $FILE &> /dev/null; then
  echo "Total blank lines: `grep "^$" $FILE | wc -l`."
else
  echo "No blank line."
fi


 

4. 練習:寫一個腳本

給定一個用戶,判斷其UIDGID是否一樣

如果一樣,就顯示此用戶爲“good guy”;否則,就顯示此用戶爲“bad guy”。

#!/bin/bash
USERNAME=user1
USERID=`id -u $USERNAME`
GROUPID=`id -g $USERNAME`
if [ $USERID -eq $GROUPID ]; then
  echo "Good guy."
else
  echo "Bad guy."
fi


 

進一步要求:不使用id命令獲得其id號;

 

#!/bin/bash
#
USERNAME=user1
if ! grep "^$USERNAME\>" /etc/passwd &> /dev/null; then
  echo "No such user: $USERNAME."
  exit 1
fi
 
USERID=`grep "^$USERNAME\>" /etc/passwd | cut -d: -f3`
GROUPID=`grep "^$USERNAME\>" /etc/passwd | cut -d: -f4`
if [ $USERID -eq $GROUPID ]; then
  echo "Good guy."
else
  echo "Bad guy."
fi


 

5. 練習:寫一個腳本

給定一個用戶,獲取其密碼警告期限;

而後判斷用戶密碼使用期限是否已經小於警告期限;

         提示:計算方法,最長使用期限減去已經使用的天數即爲剩餘使用期限;

        

如果小於,則顯示“Warning”;否則,就顯示“OK”。

 

圓整:丟棄小數點後的所有內容

 

#!/bin/bash
W=`grep "student" /etc/shadow | cut -d: -f6`
S=`date +%s`
T=`expr $S/86400`
L=`grep "^student" /etc/shadow | cut -d: -f5`
N=`grep "^student" /etc/shadow | cut -d: -f3`
SY=$[$L-$[$T-$N]]
 
if [ $SY -lt $W ]; then
  echo 'Warning'
else
  echo 'OK'
fi

 

6. 練習:寫一個腳本

判定命令歷史中歷史命令的總條目是否大於1000;如果大於,則顯示“Some command will gone.”;否則顯示“OK”。

 history | tail -1 | cut -d' ' -f1

需要去掉開頭的空格,cut 無法解決,留疑

 

shell中如何進行算術運算:

A=3

B=6

1let 算術運算表達式

         let C=$A+$B

2$[算術運算表達式]

         C=$[$A+$B]

3$((算術運算表達式))

         C=$(($A+$B))

4expr 算術運算表達式,表達式中各操作數及運算符之間要有空格,而且要使用命令引用

         C=`expr $A + $B`

 

條件判斷,控制結構:

1. 單分支if語句

if 判斷條件; then

  statement1

  statement2

  ...

fi

 

2. 雙分支的if語句:

if 判斷條件; then

         statement1

         statement2

         ...

else

         statement3

         statement4

         ...

fi

 

3. 多分支的if語句:

if 判斷條件1; then

  statement1

  ...

elif 判斷條件2; then

  statement2

  ...

elif 判斷條件3; then

  statement3

  ...

else

  statement4

  ...

fi



06_01_bash腳本編程之四 整數測試及特殊變量

     


複習:

測試方法:

[ expression ]

` expression `

test expression


bash中常用的條件測試有三種:整數,字符串,文件

整數測試:

 -gt

 -le

 -ne

 -eq

 -ge

 -lt


INT1=63

INT2=77

[ $INT1 -eq $INI2 ]

[[ $INT1 -eq $INT2 ]]

test $INT1 -eq $INT2 


文件測試:    

-e FILE:測試文件是否存在,exist的簡寫

-f FILE: 測試文件是否爲普通文件

-d FILE: 測試指定路徑是否爲目錄

-r FILE: 測試當前用戶對指定文件是否有讀取權限;

-w FILE:   ~寫權限

-x FILE:    ~執行

 

e.g: 

[ -e /etc/inittab ]

[ -x /etc/rc.d/rc.sysinit ] 

 

練習:寫一個腳本 - 答案爲filetest2.sh

給定一個文件:

如果是一個普通文件,就顯示之;

如果是一個目錄,亦顯示之;

否則,此爲無法識別之文件;

 

定義腳本退出狀態碼

exit: 退出腳本

exit #

如果腳本沒有明確定義退出狀態碼,那麼,最後執行的一條命令的退出碼即爲腳本的退出狀態碼;

 

測試腳本是否有語法錯誤:

bash -n 腳本

 

調試腳本:

bash -x 腳本:打印每步執行

 

bash變量的類型:

         本地變量(局部變量)

         環境變量

         位置變量:

                   $1, $2, ...

                   shift [n]:移出前面的n(默認爲1)個參數,後面的參數向前移

         特殊變量:

                   $?

                   $#:參數的個數

                   $*: 參數列表

                   $@:參數列表

    

e.g:     

./filetest.sh /etc/fstab /etc/inittab

$1: /etc/fstab

$2: /etc/inittab

 

練習:寫一腳本 - 答案爲 filetest3.sh

能接受一個參數(文件路徑)

判定:此參數如果是一個存在的文件,就顯示“OK.”;否則就顯示"No such file."

 

練習:寫一個腳本 - 答案爲 cacl.sh

給腳本傳遞兩個參數(整數)

顯示此兩者之和,之乘積;

#!/bin/bash

#

if [ $# -lt 2 ]; then

  echo "Usage: cacl.sh ARG1 ARG2"

  exit 8

fi

 

echo "The sum is: $[$1+$2]."

echo "The prod is: $[$1*$2]."

 

練習:寫一個腳本,完成以下任務

1、使用一個變量保存一個用戶名;

2、刪除此變量中的用戶,且一併刪除其家目錄;

3、顯示“用戶刪除完成”類的信息;

 #!/bin/bash

#

USER=user1

if userdel -r $USER; then

    echo "Delete user finished."

else

    echo "Delete user failed."

fi



06_03_bash腳本編程之五 字符串測試及for循環

        

shell編程引用變量:${VARNAME}, 括號有時可省略。

 

1. 練習: - 答案爲testuser.sh

傳遞一個用戶名參數給腳本,判斷此用戶的用戶名跟其基本組的組名是否一致,並將結果顯示出來。

#!/bin/bash

if [ 'id -nu $1' == 'id -gu $1' ]; then

fi 


字符串測試:符號兩端要有空格

==:測試是否相等,相等爲真,不等爲假

!=:測試是否不等,不等爲真,等爲假

>:一般不用

< :一般不用

-z string: 測試指定字符串是否爲空,空則真,不空則假

-n string: 測試指定字符串是否不空,不空爲真,空則爲假

 

2. 練習:寫一個腳本

傳遞一個參數(單字符就行)給腳本,如參數爲q,就退出腳本;否則,就顯示用戶的參數;

 

3. 練習:寫一個腳本

傳遞一個參數(單字符就行)給腳本,如參數爲qQquitQuit,就退出腳本;否則,就顯示用戶的參數;

#!/bin/bash

if [ $1 = 'q' ];then

  echo "Quiting..."

  exit 1

elif [ $1 = 'Q' ];then

  echo "Quiting..."

  exit 2 

elif [ $1 = 'quit' ];then

  echo "Quiting..."

  exit 3

elif [ $1 = 'Quit' ];then

  echo "Quiting..."

  exit 4 

else

  echo $1

fi

 

4. 練習:

傳遞三個參數給腳本,第一個爲整數,第二個爲算術運算符,第三個爲整數,將計算結果顯示出來,要求保留兩位精度。形如:

./calc.sh 5 / 2

提示:

scale=2保留兩位精度

echo "scale=2;111/22;" | bc

bc <<< "scale=2;111/22;" 


#!/bin/bash

if [ $# -lt 3 ]; then 

    echo "Usage: `basename $0` num1 opt num2"

    exit 1

fi

bc <<< "scale=2;$1 $2 $3"


5. 練習:

傳遞3個參數給腳本,參數均爲用戶名。將此些用戶的帳號信息提取出來後放置於/tmp/testusers.txt文件中,並要求每一行行首有行號。

        

6. 練習,寫一個腳本:

判斷當前主機的CPU生產商,其信息在/proc/cpuinfo文件中vendor_id一行中。

如果其生產商爲AuthenticAMD,就顯示其爲AMD公司;

如果其生產商爲GenuineIntel,就顯示其爲Intel公司;

否則,就說其爲非主流公司;


#!/bin/bash

VENDOR_ID=`grep vendor_id /proc/cpuinfo | head -1 | cut -d' ' -f2` 

if [ $VENDOR_ID == "AuthenticAMD" ]; then

    echo "AMD company"

elif [ $VENDOR_ID == "GenuineIntel" ]; then

    echo "Intel company"

fi


7. 練習,寫一個腳本:

給腳本傳遞三個整數,判斷其中的最大數和最小數,並顯示出來。

MAX=0

MAX -eq $1

MAX=$1

MAX -lt $2

MAX=$2

 

 

循環:一定要有:進入條件,退出條件

1. for

2. while

3. until

 

for循環語句

for 變量 in 列表; do

  循環體

done


列表遍歷完成之後,退出; 


e.g:

for I in 1 2 3 4 5 6 7 8 9 10; do

  加法運算

done

 

如何生成列表:

1. {1..100}

2. seq命令:`seq [起始數 [步進長度]] 結束數`,

 

8. 練習:求1-100的和 - 答案爲sum.sh


declare: 

         -i: 將一個變量聲明爲整型,integer

         -x: 將一個變量聲明爲環境變量

e.g: declare -i SUM=0


9. 寫一個腳本:

1、設定變量FILE的值爲/etc/passwd

2、依次向/etc/passwd中的每個用戶問好,並顯示對方的shell,形如: 

         Hello, root, your shell: /bin/bash

3、統計一共有多少個用戶

 

for I in `seq 1 $LINES`; do echo "Hello, `head -n $I /etc/passwd | tail -1 | cut -d: -f1`"; done

 

只向默認shellbash的用戶問聲好

 




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章