高級shell編程講解

高級Shell編程

 

目錄

1.shell腳本的執行方法   2.shell的變量類型   3.shell特殊變量

4.變量子串的常用操作   5.批量修改文件名實踐    6.變量替換

7.在shell中計算字符串長度的方法    8.變量的數值計算:(()) 的用法

9. 變量的數值計算:let的用法    10.變量的數值計算:expr的用法

11.變量的數值計算:bc的用法      12.條件測試的多種方法

13.字符串測試操作符          14.整數二元比較操作符

15.邏輯操作符              16.利用shell知識製作單級及多級菜單

17.case結構條件語句       18. 當型循環和直到型循

19.for循環

 

       

待續。。。

 

1.shell腳本的執行方法返回目錄

當shell腳本以非交互的方式運行時,它會先查找環境變量ENV,該變量指定了一個環境文件(通常是.bashrc),然後從該環境變量文件開始執行,當讀取了ENV文件後,SHELL纔開始執行shell腳本中的內容。

shell腳本的執行通常可以採用以下三種方法:

  1. bash script-name 或者 sh script-name
  2. path/script-name 或者 ./script-name(當前路徑下執行)
  3. source script-name 或 . script-name(注意符號“.”與 script-name之間有空格)

第一種方法是腳本文件本身沒有可執行權限時,通常使用的方法;

第二種方法需要先將腳本文件的權限改爲可執行,然後通過腳本路徑就可以直接執行;

第三中方法是在當前shell環境中直接執行,而不是新創建一個子shell,當我們需要在一個腳本中使用另一個腳本中的變量的時候就使用第三種方法,例如創建如下腳本,其中定義了chars變量:

 

通過上面三種方法執行:

 

可以看出方法1,2執行腳本是系統會自動新創建一個子shell,執行之後,其變量不會在當前shell有效,而第三種方法是告訴系統讓這個腳本直接在當前shell執行,顯然其定義的變量chars在當前shell中也是有效的,所以需要在某個腳本中使用另外一個腳本中的變量時,需要使用第3中方法執行腳本。

2.shell的變量類型 返回目錄

shell中的變量分爲環境變量和全局變量

  環境變量也稱爲全局變量,可以在創建他們的shell及其派生的任意子進程shell中使用。局部變量只能使用在創建它們的shell函數或腳本中使用。

  環境變量用於定義Shell的運行環境,保證shell命令的正確執行,shell通過環境變量來確定登錄用戶名,命令路徑,終端類型,登錄目錄。環境變量可以在命令行中設置,但用戶退出時這些變量值也會丟失,因此最好在用戶家目錄下的.bash_ptofile文件會全局配置/etc/profile文件或者/etc/profile.d中定義,將環境變量放入profile中,每次用戶登錄,這些變量值都將被初始化。

  傳統上,所有環境變量均爲大寫。環境變量用於用戶進程前,必須用export命令導出。

  有一些環境變量,比如HOME,PATH,SHELL,UID,USER等在用戶登錄之前就已經被/bin/login程序設置了,通常環境變量的定義並保存在用戶的家目錄下的./bash_profile文件中。

  已經定義的變量可以用unset在取消定義。

本地變量定義的三種方式:

var_name=value

var_name='value'

var_name="value"

下面看看這三種方式的區別

 

第一種方法是直接定義變量內容,但是內容必須連續,中間不能有空格字符;

接着看下面:

 

第二種方法通過單引號定義變量,只會原樣輸出字符串內容,而不會對字符串中的變量和特殊字符進行解析,適合定義單純字符顯示;

第一種和第三種,輸出時,會對內容進行解析,輸出解析後的內容,有於第一種方法不能定義不連續的變量,所以通常在需要解析的時候都加上雙引號,而很少使用第一種方法,第一種方法一般僅僅用來定義連續的數字或者路徑。

3.shell的特殊變量 返回目錄

  位置變量

$0$0 獲取當前執行腳本的文件名,包括路徑;

$n$n,獲取當前執行的shell腳本的第n個參數,n=1,...,9,如果 n 大於9, 使用大括號${10};

$$∗ 獲取當前shell的所有參數,將命令行參數視爲單個字符串,相當於"$1$2$3...$n""$1$2$3...$n"

$$# 獲取當前shell腳本或者命令行參數的總個數;

$$@ 這個程序的所有參數 "$1""$2""$3""...","$1""$2""$3""...",這是將參數傳遞給其他程序的最佳方式,因爲它會保留所有內嵌在每個參數裏的任何空白。

  進程狀態變量

$$$$ 獲取當前shell的進程號(PID)

$$? 獲取上一個指令的返回值(0 爲成功,非零爲失敗)

4.變量子串的常用操作 返回目錄

常用操作
編號 表達式 說明
1 ${#string} 返回$string的長度
2 ${string:position} 在$string中,從位置position之後開始提取子串
3 ${string:position:length} stringpositionstring中,從位置position之後開始提取長度爲length的子串
4 ${string#substring} 從變量stringstring開頭刪除最短匹配substring子串
5 ${string##substring} 從變量stringstring開頭刪除最長匹配substring子串
6 ${string%substring} 從變量stringstring結尾刪除最短匹配substring子串
7 ${string%%substring} 從變量stringstring結尾刪除最長匹配substring子串
8 ${string/substring/replace} 使用replacereplace來代替第一個匹配的substring
9 ${string//substring/replace} 使用replacereplace來代替所有匹配的substring
10 ${string/#substring/replace} 如果stringstring前綴匹配substring,就用replacereplace來代替匹配的字符串substring
11 ${string/%substring/replace} 如果stringstring後綴匹配substring,就用replacereplace來代替匹配的字符串substring

 

舉例說明如下:

 

5.批量修改文件名實踐 返回目錄

例如有下面的文件:

 

現在想要將後綴前部改爲大寫JPG:

方法一:

#!/bin/bash
for obj in $(ls *.jpg)
do
    mv ${obj} $(echo ${obj/%jpg/JPG})
done

方法二:

rename 's/jpg$/JPG/' *.jpg

 

 

6.變量替換 返回目錄

運算符號 作用
${value:-word}

如果變量名存在且非null,返回變量值;否則,返回word字符串

用途:如果變量未定義,則返回默認值

${value:=word}

如果變量名存在且非null,返回變量值;否則,設置這個變量值爲word

用途:如果變量未定義,,則設置變量爲默認值,並返回默認值

${value:?"not defined"}

如果變量名存在且非null,返回變量值;否則顯示“not defined”,並退出當前命令或腳本。

用途:用於捕捉由於變量未定義而導致的錯誤,並退出程序。

${value:+word}

如果變量名存在且非null,返回word,否則返回null。

用途:測試變量是否存在。

示例如下:

 

 

7.在shell中計算字符串長度的方法返回目錄

建立一個字符串:

注意:使用 wc -m 的方法會計算換行符,因爲echo會在輸出完字符串之後自動加上一個換行符,使用echo -n 會去掉換行符:

 

比較上面三種方法的效率:

 

time :

獲取一個程序的執行時間,可以獲取到實際運行時間以及程序在用戶態和內核態分別的時間,大部分的性能測試,可能只需要關注實際(real)時間

看到上面三種獲取字符串長度的速度相差幾十倍到上百倍,一般調用外部命令處理,與內置功能性能相差很大。所以在shell編程,儘量使用內置操作或函數完成。 

 8.變量的數值計算:(())的用法 返回目錄

(1) (())用法:(此法很常用,且效率高)

用於執行的整數運算,支持的運算符與C語言中的基本一致,除了特別注意 "**" 在 (()) 中表示冪運算,而C語言不支持,如 ((2**3)) 結果是 8.

 示例:

 

注意:1)**表示冪運算

   2)上面涉及的變量元素必須爲整型,不能是小數和字符,涉及小數的後面使用 bc 可以實現。

 (()) 內部的變量可以不用加$$ 符號:

 各種shell運算的腳本例子:

 實踐:用shell腳本編寫一個實現加,減,乘,除的計算器:

9. 變量的數值計算:let的用法 返回目錄

與 ((表達式)) 功能一致,但是沒有 (()) 的計算效率高,所以常用 (()),而不去使用let.

 

10.變量的數值計算:expr的用法 返回目錄

expr命令一般用於整數計算,但也可用於字符串,用來求表達式變量的值,同時expr也是一個手工命令計算器。

 

expr 的語法不是很好,所以不常用,這裏標記,保證看到別人使用的時候,自己能夠看懂。

下面介紹expr比較好用兩個技巧

  1)檢查某個文件是否是某一類型或擴展名:

  

  2)判斷一個變量是否是整數:

  

  寫出判斷一個輸入是否爲整數的腳本:

  

  

 11.變量的數值計算:bc的用法 返回目錄

bc支持科學計算

  

 

  使用shell編寫輸出楊輝三角的腳本:

  

複製代碼
#!/bin/bash

export LANG="zh_CN.GB18030"

#本文內容來自《老男孩linux運維實戰培訓中心》shell 編程部分學生練習資料

#如果腳本後面沒有參數,提示輸入一個參數
if ( test -z $1 );then
    read -p "Input max int lines:" MAX 
else
    MAX=$1
fi

#判斷參數的合法性
#將參數中的數字全部替換爲空,然後判斷替換後的內容是否爲空
#若不爲空,表明參數中含有非數字的其他非數字內容,則不合法
#“[ ]”的功能與test一致,可以 man test 查看
[ -n "$(echo ${MAX}|sed 's/[0-9]//g')" ] && \
echo "The number you input must be int(1-9)" && exit 1

#將輸入限制在小於10
[ ! ${MAX} -lt 10 ] && \
echo "The number you input must be int(1-9)" && exit 1

#start
a[0]=1
for ((i=0;i<MAX;i++))
do
    for ((j=$i;j>0;j--))
    do
        ((a[$j]+=a[$j-1]))
    done

    for ((j=0;j<=MAX-i;j++))
    do
        if ((MAX<=6));then
            echo -en "\t"
        else
            echo -n "    "
        fi
    done

    for ((j=0;j<=i;j++))
    do
        if [ ${MAX} -le 6 ];then
            echo -en "\t\t"${a[$j]}
        else
            echo -en ${a[$j]}
        fi
    done
echo
done
複製代碼

 

運行結果:

 12.條件測試的多種方法 返回目錄

語法格式:

格式1:test expression 

格式2:[ expression ]

格式3:[[ 測試表達式 ]]

注:中括號與表達式之間前後都有空格

格式1與格式2是等價的;格式3爲擴展的test命令,在 [[  ]] 中可以使用通配符進行模式匹配,如&&,||,>, <等操作符可以應用於[[ ]]中,但不能應用於[ ]中;對整數的關係運算,也可以使用Shell的算術運算符 (()).

關於各種測試操作符只需要在終端man test 即可得到詳細描述:

常用的文件測試操作符號 說明
-f file 若文件存在且爲普通文件則真
-d file 若文件存在且爲目錄則真
-s file 若文件存在且不爲空(文件大小非0)則真
-e file   若文件存在則真,區別於-f
-r file 若文件存在且可讀則真
-w file   若文件存在且可寫則真
-x file 若文件存在且可執行則真
-L file   若文件存在且爲鏈接文件則真
f1 -nt f2   若文件f1 比文件 f2 新則真
f1 -ot f2 若文件f1 比文件 f2 舊則真

13.字符串測試操作符 返回目錄

  字符串測試操作符的作用:比較兩個字符串是否相同、字符串長度是否爲0,字符串是否爲null等

  “=”比較兩個字符串是否相同,與 “==”等價,如 if [ "$a$a"="$b$b" ],其中 $a$a 這樣的變量最好用雙引號括起來。

字符串測試操作符
常用字符串測試操作符 說明
-z "string" 若string長度爲0,則真
-n "string" 若string長度步爲0,則真
“string1”= ”string2“ 若string1等於string2則真,可以使用“==”代替“=”
“string1”!= ”string2“ 若string1不等於string2則真

 

  注意:測試符“==”,“=”,“!=”好前後均需與測試字符串之間留空格!!!

14.整數二元比較操作符 返回目錄

 

在[  ]中使用的比較符 在(())和[[]]中使用的比較符 說明
-eq ==   相等
-ne != 不等
-gt > 大於
-ge >= 大於或等於
-lt < 小於
-le   <= 小於或等於

 

15.邏輯操作符 返回目錄

在[]中的使用 在[[]]中的使用 說明
-a && 與,兩端均爲真則真
-o || 或,兩端有一個爲真則真
! ! 非,相反則真

16.利用shell知識製作單級及多級菜單 返回目錄

 

 17.case結構條件語句 返回目錄

 

語法:

case "字符串變量" in

  值1)指令1...

;;

  值2)指令2...

;;

  *)指令

;;

esca

 給字符串顯示不同的顏色:

shell腳本中echo可以顯示不同顏色的字符,格式如下:

  echo -e "\033[字背景顏色;文字顏色m字符串\033[0m"
  例如:
  echo -e "\033[41;36m something here \033[0m"
  其中41的位置代表底色, 36的位置是代表字的顏色
  1、字背景顏色和文字顏色之間是英文的";"
  2、文字顏色後面有個m
  3、字符串前後可以沒有空格,如果有的話,輸出也是同樣有空格

下面利用case來該給定的字符串加上不同的顏色:

複製代碼
 1 #!/bin/bash
 2 #Paint given chars with given color
 3 usage="Usage:chars {black|red|green|yellow|blue|purple|white}"
 4  [[ $# -ne 2 ]] &&{ 
 5      echo "${usage}" 
 6      exit 1
 7 }
 8 BLACK="\033[1;30m"; RED="\033[1;31m" ;GREEN="\033[1;32m"; YELLOW="\033[1;33m"
 9 BLUE="\033[1;34m"; PRUPLE="\033[1;35m"; WHITE="\033[1;37m"
10 COLOR_END="\033[0m"
11 
12 chars=$1
13 selected_color=$2
14 
15 case ${selected_color} in
16     black) res=${BLACK}
17 ;;
18     red) res=${RED}
19 ;;
20     green) res=${GREEN}
21 ;;
22     yellow) res=${YELLOW}
23 ;;
24     blue) res=${BLUE}
25 ;;
26     purple) res=${PURPLE}
27 ;;
28     white) res=${WHITE}
29 ;;
30     *) echo 'Input color is not supported'
31        echo ${usage}
32        exit 1
33 ;;
34 esac
35 
36 echo -e "${res}"$1"${COLOR_END}"
複製代碼

18. 當型循環和直到型循環  返回目錄

 

while條件語句,條件滿足一直執行command

while condition
    do
    command
done

 

until語法,條件滿足就退出,目前很少用,作爲了解

until condition
    do
    command
done

 

複製代碼
#!/bin/bash
i=10
while (($i>=1))
do
    echo $i
    ((i--))
done
複製代碼

 

使用until實現上面同樣的功能:

複製代碼
#!/bin/bash

i=10
until [ $i -eq 0 ] 
do
    echo $i
    (( i-- ))
done
複製代碼

 在實踐中經常需要使用while來處理日誌文件,下面實際中使用while讀取文本的方法:

複製代碼
#1
exec <FILE
while read line
do
    cmd
done

#2
cat ${FILE} | while read line
do
    cmd
done

#3
while read line
do
    cmd
done<FILE
複製代碼

 

19.for循環 返回目錄

 

for循環語法結構1:

複製代碼
for var in var_list
do
    cmd1
    cmd2
    ...
done
複製代碼

 

在此結構中, “in var_list”可以省略,省略時,相當於in "@",foriforiin"@",例如fori就相當於foriin"@".

for循環語法結構2:

複製代碼
for ((exp1;exp2;exp3)) #與C語言一樣
do
    cmd1
    cmd2
    ...
done
複製代碼
#!/bin/bash
for i in 10 9 8 7 6 
do
    echo $i
done

下面代碼實現同樣的功能:

#!/bin/bash
for i in {10..6}
do
    echo $i
done

 

#!/bin/bash
for i in $(seq -s " " 10 -1 6)
do
    echo $i
done

 

獲取當前目錄下的所有文件名,打印

#!/bin/bash
for i in $(ls) 
do
    echo $i
done

 

打印9*9乘法表:

複製代碼
 1 #!/bin/bash
 2 for a in $( seq 1 9 )
 3 do
 4     for b in $( seq 1 9 )
 5     do  
 6         if [ $a -ge $b ];then
 7             echo -en "$a x $b = $((a*b))  "
 8         fi  
 9     done
10 echo " "
11 done
12 
13 echo
複製代碼

 

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