shell腳本語言編程之bash
shell簡介
什么是shell: shell是Linux的用戶界面,提供了用戶與內核進行交互的接口,他接收了用戶的指令,并將指令送入內核去執行 shell即是一種高級程序語言,也是一種命令解析語言 shell腳本有點: 開發簡單、可移植性強(使用POSIX所定義的功能)、簡單性 shell編程: 用于系統管理工作,或是結合現有的程序或命令完成小型的或特定的工作。 編程語言分類以及工作原理 編譯語言:高級語言-- >編譯器-- >目標代碼 編譯語言源代碼運行時需要編譯器轉換成程序文件,編譯語言舉例: java, C# 解釋語言:高級語言-- >解釋器-- >機器代碼 由解析器直接讀入代碼,將其轉換成內部形式 ,解析語言舉例:shell, perl, python 編譯模型: 過程式:以指令為中心,數據服務于代碼 面向對象式:以數據為中心指令服務于數據 shell編程格式: 首行shebang機制 #!/bin/bash shell腳本用途: 自動化常用命令 執行系統管理和故障排除 創建簡單的應用程序 處理文本或文件
創建shell腳本
第一步:創建本文文件,首行添加#!/bin/bash #注釋 第二步:運行腳本
shell腳本運行
一、給予執行權限,在命令行上指定腳本的絕對或相對路徑 二、直接運行解釋器,將腳本作為解釋器程序的參數運行
shell腳本第一個實例:hello word
bash腳本調試
bash - n /path/to/some_script 檢測腳本中的語法錯誤 bash - x /path/to/some_script 調試執行
腳本變量
變量:命名的內存空間 數據存儲方式: 字符: 數值:整型,浮點型 作用: 1、數據存儲格式 2、參與的運算 3、表示的數據范圍 類型: 字符 數值:整型、浮點型 變量命名法則: 1、不能使程序中的保留字:例如if, for; 2、只能使用數字、字母及下劃線,且不能以數字開頭 3、見名知義 4、統一命名規則:駝峰命名法 shell中變量屬于弱引用,無須指定類型,默認均為字符型;參與運算會自動進行隱式類型轉換;變量無須事先定義可直接調用 如: bash 不支持浮點數 bash中的變量種類 本地變量:僅對當前shell進程生效 環境變量:對當前shell以及子shell生效 局部變量:生效范圍為當前shell進程中某代碼片斷(通常指函數) 位置變量:$1, $2, ...來表示,用于讓腳本在腳本代碼中調用通過命令行傳遞給它的參數 特殊變量:$?, $0, $*, $@, $#
本地變量
變量賦值: name=‘value’, 以下是變量可引用的值: 1、可以是直接字串:name=“root"(注意等號左右兩邊不能有空格哦) 2、變量引用:name="$USER" 3、命令引用:name=`COMMAND`, name=$(COMMAND) 變量引用: ${name}, $name 三種引號使用!?。。。? "":弱引用,其中的變量引用會被替換為變量值 '':強引用,其中的變量引用不會被替換為變量值,而保持原字符串 ``:能識別命令 顯示已定義的所有變量: set 刪除變量: unset name
證明環境變量只能在當前shell中使用
在當前shell中定義變量name=wangNN ——>在打開一個子shell輸出name變量為空 pstree :顯示進程樹??梢圆榭串斍敖K端shell的結構
bash腳本編程小試牛刀:
1、編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名, IPv4地址,操作系統版本,內核版本,CPU型號,內存大 硬盤大小。
[root@centos7 bin]# cat systeminfo.sh #!/bin/bash echo "the hostname is:`hostname`" echo "localhost IPV4 is:`ifconfig |sed -n "2p" |sed -e "s@.*inet@@" -e "s@netmask.*@@" `" echo "the operation bersion is:`cat /etc/centos-release`" echo "the kenel information is:`uname -r`" echo "the cpu is:`lscpu |head -1|sed "s@.*[[:space:]]\+\b@@"`" echo "the member size is:`cat /proc/meminfo |head -1 |tr -s " "|cut -d " " -f 2,3`" echo "the hard /dev/sda size is:`fdisk -l |grep sda|head -1|sed "s@.*:@@"|sed "s/,.*//"`" echo "the hard /dev/sdb size is:`fdisk -l |grep sdb|head -1|sed "s@.*:@@"|sed "s/,.*//"`" [root@centos7 bin]#
2、編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY- mm- dd中
3、編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值
4、編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序
環境變量
變量聲明和賦值 export name="value" declare -x 變量名=值 變量引用 $name ${name} 顯示所有環境變量 env export printenv 刪除變量:unset 變量名
證明環境變量可以在子shell中應用
定義環境變量——>bash 進入子shell ——>echo $name發現變量有值
只讀變量:
只讀變量:只能聲明,不能刪除,退出當前shell之后自動消失
位置參數變量
$?:上一條執行命令結果,0成功1代表失敗 $0:當前shell類型 $@:將傳遞的參數展開成多個參數 $*:將傳遞的參數作為一個整體 $#:目前進程中的參數個數
$*和$@區別
$*和$@都指傳遞多個參數,單獨打印時,不能看出區別,當下一個腳本調用時$@ 將傳遞的參數展開成多個,$*將多個參數捆綁在一起
只有添加" "他們才會有區別,不加" "$*默認將多個參數展開成多個參數進行傳遞
bash中的算數運算符
+, - , *(使用時需要\進行轉義), /, %取模(取余) , **(乘方) bash 中實現算數運算的幾種方法: 1、let var=算數表達式 2、var=$[算數表達式] 3、var=$((算數表達式)) 4、var=$(expr $num1 + $num2 ) 5、declare -i var=數值 echo "算數表達式" |bc (如果是數值 1+2 可以是用'',如果引用的是變量就要使用"$num1+$num2") bash有內建的隨機數生成器: $RANDOM( 1 - 32767) echo $[$RANDOM%50] : 0- 49之間隨機數
實現算數運算的方法
1、使用let let:求算是表達式中的值
2、使用[] [:內置命令,判斷條件表達式,與test同義,但是必須使用]結尾。
3、使用(())
4、使用expr expr :只能計算整數,并且表達式每個參數之間要添加空格
賦值
增強型賦值: +=, - =, *=, /=, %= let count+=3 自加3后自賦值 自增,自減: let var+=1 let var++ let var- =1 let var--
練習二
練習 1:寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和
[root@centos7 bin]# cat sumid.sh #!/bin/bash #author:wangNanNan #time:20160810 #fuction:calculate the sum of the two userID userID1=`cat /etc/passwd |sed -n "10p" |cut -d: -f3` userID2=`cat /etc/passwd |sed -n "20p" |cut -d: -f3` SUM=$[userID1+userID2] echo "the sum of he tenth userID and the twenth usrID is:$SUM" unset userID1 unset userID2 unset SUM [root@centos7 bin]#
練習 2:寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和
[root@centos7 bin]# cat sumspace.sh #!/bin/bash #author:wangnannan #time:20160810 #function:calculate the sumspace of the two file fistFileSpace=`grep -c '^$' $1 ` secondFileSpace=`grep -c '^$' $2 ` sum=$[ fistFileSpace + secondFileSpace ] echo "兩個文件空白行之和為:$sum" unset fistFileSpace unset secondFileSpace unset sum [root@centos7 bin]#
練習 3:寫一個腳本/root/bin/sumfile.sh,統計/etc, /var,/usr目錄中共有多少個一級子目錄和文件
邏輯運算符
非:! 與:& 或:|
與:兩個數字或條件進項進行與運算,其中有一個為假,結果為假
或:兩個數字或條件進項進行與運算,其中有一個為真,結果為真
短路與: 第一個為0,結果必定為0; 第一個為1,第二個必須要參與運算; 短路或: 第一個為1,結果必定為1; 第一個為0,第二個必須要參與運算; 異或: ^ 異或的兩個值,相同為假,不同為真
聚合命令
復合式: date; who | wc - l 命令會一個接一個地運行 ? 子shell: (date; who | wc - l ) >>/tmp/trace所有的輸出都被發送給單個STDOUT和STDERR
退出狀態
進程使用退出狀態來報告成功或失敗 0:代表成功 1-255:代表失敗 例如: $ ping - c1 - W1 hostdown &> /dev/null $ echo $? 自定義bash退出狀態碼 exit[n]; shell 腳本遇到exit,會立即退出,退出狀態碼取決于exit[]后面的數字,如果未定義,取決于腳本最后一條命令執行的狀態碼
條件測試
測試命令: ? test EXPRESSION ? [ EXPRESSION ] ? [[ EXPRESSION ]] 注意: EXPRESSION前后必須有空白字符 test命令:檢測文件類型或比較值是否相等 格式:test 表達式 test命令兩種格式: 長格式:test $A=$B 短格式:[ "$A" == "$B" ] 數值類測試: -eq:是否等于 -ge:是否大于等于 -le:是否小于等于 -gt:是否大于 -lt:是否小于 -ne:是否不等于 字符串類測試: ==:是否等于; >: ascii碼是否大于ascii碼 <: 是否小于 !=: 是否不等于 =~: 左側字符串是否能夠被右側的PATTERN所匹配,此表達式一般用于[[ ]]中; - z "STRING":字符串是否為空,空為真,不空為假 - n "STRING":字符串是否不空,不空為真,空為假 注意:用于字符串比較時的用到的操作數都應該使用引號
練習題:
1、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出; 如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數 [root@centos7 bin]# cat argsum.sh #!/bin/bash #author=wangnannan #time=20160810 #function:argument count [[ $# -lt 1 ]] && echo "Should at least give a parameter;`exit`" || echo "the first file Blank row :`grep -c "^$" $1`" [root@centos7 bin]#
2、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,測試是否可連通。如果能ping通,則提 示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問 ” [root@centos7 bin]# cat hostping.sh #!/bin/bash #author:wangnannan #time20160810 #fuction:test one host can bi communicate echo -e "please input the ipv4\c" read ipv4 ping -c1 $ipv4 && echo "the host can be arrive" || echo "the host no arrive" [root@centos7 bin]#
文件測試
存在性測試 - a FILE:同- e - e FILE: 文件存在性測試,存在為真,否則為假; 存在性及類別測試 - b FILE:是否存在且為塊設備文件; - c FILE:是否存在且為字符設備文件; - d FILE:是否存在且為目錄文件; - f FILE:是否存在且為普通文件; - h FILE 或 - L FILE:存在且為符號鏈接文件; - p FILE:是否存在且為命名管道文件; - S FILE:是否存在且為套接字文件; 文件權限測試: - r FILE:是否存在且可讀 - w FILE: 是否存在且可寫 - x FILE: 是否存在且可執行 文件特殊權限測試: - g FILE:是否存在且擁有sgid權限; - u FILE:是否存在且擁有suid權限; - k FILE:是否存在且擁有sticky權限; 文件大小測試: - s FILE: 是否存在且非空; 文件是否打開: - t fd: fd表示文件描述符是否已經打開且與某終端相關 - N FILE:文件自動上一次被讀取之后是否被修改過 - O FILE:當前有效用戶是否為文件屬主 - G FILE:當前有效用戶是否為文件屬組 雙目測試: FILE1 - ef FILE2: FILE1與FILE2是否指向同一個設備上的相同inode FILE1 - nt FILE2: FILE1是否新于FILE2; FILE1 - ot FILE2: FILE1是否舊于FILE2;
文件測試小練習:
1、檢測文件是否存在
2、檢測兩個文件是否為硬鏈接
組合測試:
第一種方式: COMMAND1 && COMMAND2 并且 COMMAND1 || COMMAND2 或者 ! COMMAND 非 如: [ - e FILE ] && [ - r FILE ] 第二種方式: EXPRESSION1 - a EXPRESSION2 并且 EXPRESSION1 - o EXPRESSION2 或者 ! EXPRESSION 必須使用測試命令進行; [ - z “$HOSTNAME” - o $HOSTNAME "==\"localhost.localdomain" ] && hostname www.magedu.com
練習題
1、 chmod - rw /tmp/file1,編寫腳本/root/bin/per.sh,判斷當前用戶對/tmp/fiile1文件 是否不可讀且不可寫 [root@centos7 bin]# cat per.sh #!/bin/bash [ ! -r /tmp/file1 -a ! -w /tmp/file1 ] && echo "`whoami` can not read and not write " || echo "`whoami` can read or write " [root@centos7 bin]# 注意:在普通用戶下去運行,root不受權限限制 2、編寫腳本/root/bin/nologin.sh和login.sh,實現禁止和充許普通用戶登錄系統。 [root@centos7 bin]# cat login.sh #!/bin/bash [ -a /etc/nologin ] && echo "common user is not login" || (touch /etc/nologin;echo "add file complete") [root@centos7 bin]#
使用read命令接受輸入參數
read [option]
-p:不換行接受輸入
-t:接受輸入時間,超過指定時間將推出程序
終極練習
1、指定文件做為參數,判斷文件是否為.sh后綴,如果是,添加x權限 [root@centos7 bin]# cat file.sh #!/bin/bash echo -e "please input filename:\c" read filename ! [ -e $filename ] && echo "the file not exit;" && exit ! [[ $filename == "/.*(\.sh)\b/" ]] && echo "please input .sh file;`exit`" [ -x $filename ] && echo "the file have x" || chmod +x $filename [root@centos7 bin]#
2、判斷輸入的IP是否為合法IP [root@centos7 bin]# cat ipcheck.sh #!/bin/bash #author:wangnannan read -p "please input IPv4:" ipv4 echo $ipv4 |egrep -q "^(\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>.){3}\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>$" && echo "ip legal" || echo "this ip is not legal" [root@centos7 bin]# vim ipcheck.sh [root@centos7 bin]#
3、計算1~100的值
[root@centos7 bin]# cat sum100.sh #!/bin/sh #author:wangnannan #description:sum 1-100 echo "caculate 1-100 sum:" for i in {1..100};do sum=$[$sum+$i] done echo "sum is:$sum" exit [root@centos7 bin]# 方法二 [root@centos7 bin]# cat sum1002.sh #!/bin/bash int=`seq 1 100` echo $int |tr " " "+" |bc [root@centos7 bin]# 方法三 [root@centos7 bin]# seq -s + 1 100 |bc 5050 [root@centos7 bin]#
4、輸入起始值A和最后值B,計算從A+(A+1)...+(B-1)+B的總和 [root@centos7 bin]# cat AB.sh #!/bin/bash read -p "plese the first num:" A read -p "plese the second num:" B [ $A -gt $B ] && echo "input error" && exit ||echo "A..B的和:` seq -s + $A $B |bc`" [root@centos7 bin]#
原創文章,作者:wangnannan,如若轉載,請注明出處:http://www.www58058.com/33909
文章內容清晰,圖文并貌,內容豐滿,有理論有實踐,