Shell編程基礎

Shell編程

一.程序簡介

程序

程序:算法+數據結構
數據結構:數據在計算機中的類型和組織方式
算法:處理數據的方式

面向過程:以指令爲中心,數據服務於指令
面向對象:以數據爲中心,指令服務於數據

計算機:二進制執行

高級編程語言:

編譯:高級語言->編譯器->機器代碼->執行
解釋:高級語言->執行->解釋器->機器代碼 shell

三大邏輯

順序、循環、選擇

二.shell腳本

1.格式

格式要求:首行shebang機制
#!/bin/bash  指定shell類型
# 註釋
程序名,作用說明,版本信息,作者信息

bash -n 檢查語法錯誤
bash -x 跟蹤調試腳本的執行過程

2.變量

變量的類型:

字符、整型
強類型
弱類型
不需要聲明變量類型
不支持浮點型
都以字符串的形式存儲

命名規則:

不能是內部命令、系統關鍵字
字母、數字、下劃線
不能以數字開頭

定義變量

a=linux
a='linux'
a="linux"
上面三個都是把linux這個字符串賦值給變量a,如果賦值的一方當中沒有空格,則不用引號,如果有空格則必須用引號。

使用變量

echo $a
echo ${a}
調用變量a,在變量前面加上$即可,變量用{}括起來是個良好的習慣

已經定義的變量也可以重新賦值
a=centos
unset a 刪除變量
readonly a 只讀變量,不能修改

單雙引號的區別

單引號 '' 強引用,單引號裏所有內容都作爲字符輸出
雙引號 "" 若引用,雙引號裏有變量的時候,會讀取變量值輸出,而不是直接輸出

把命令執行結果賦值給變量

a=`cat /etc/fstab` 使用反向單引號
a=$(cat /etc/fstab) 使用$()
反向單引號容易和單引號混淆,因此推薦使用$()

局部變量和全局變量

局部變量:生效範圍是當前shell進程 
全局變量:生效範圍是當前shell及其子進程
export a 聲明全局變量
set 顯示變量,自定義和系統自帶的
export 或 declare 顯示環境變量

echo $PPID 顯示父進程編號
pstree -p 顯示進程信息
source 運行的腳本在本bash環境下,會修改某些當前bash下的環境。
bash  運行腳本時會新開一個bash,爲當前bash的子進程,不會影響當前環境

SHLVL 變量,shell 的嵌套深度
echo $_ 上一個命令的最後一個字符串
unset name 刪除變量,除了只讀變量
readonly 查看只讀變量  declare -r 

(umask=0022;touch a) 
() 不開啓子進程
{} 開啓子進程

位置變量

$$ 當前shell的ID
$1 第一個參數
$* 所有參數,認爲所有參數是一個整體
$@ 所有參數,認爲所有參數是獨立的個體
$# 參數數量
$0 當前腳本的文件名
10以上的加{}
shift n 變量按順序往前移動n個變量
set -- 清除變量

退出狀態

$? 變量保存最近(前一個)的命令退出狀態
0 代表成功,1-255 代表失敗
腳本里指定返回值 exit 10 

2.運算

bash支持算術運算、關係運算、布爾運算、字符串運算和文件測試運算等

算術運算

expr 2 + 4
echo `expr 2 + 4
a=`expr 2 + 4`
c=`expr $a + $b`
expr是一款表達式計算工具,數值和運算符之間必須有空格,調用整個表達式的時候記得加``

let sum=x+y
$[x+y]
$((x+y))
expr 2 + 3 expr是一個命令
declare -i n=10  指定n是個整數,聲明變量
-= += -- ++ 
運算符 說明 舉例
+ 加法 `expr $a + $b
- 減法 `expr $a - $b
* 乘法 `expr $a \* $b
/ 除法 `expr $a / $b
% 取餘 `expr $a % $b
= 賦值 a=$b
== 比較兩個數字是否相等 [ $a == $b ]
!= 比較兩個數是否不等 [ $a != $b ]

表達式和[ ]之間需要有空格

邏輯運算

true 1 ;false 0;
與 & 有0即0
或 | 有1即1
非 ! 取反
短路與 && 前一個爲假則不再判斷第二個
短路或 || 前一個爲真則不再判斷第二個
異或 ^ 相同爲假,相異爲真
同或 相同爲真,相異爲假

測試命令:

test 不支持正則表達式,沒值就爲假,變量加“” 
[[]] 支持正則表達式
[]  有值就爲真
[] 和變量之間要加空格

幾種括號的用法

(; ; ) 幾個命令一起執行,開啓子shell
{; ; } 幾個命令一起執行,不開啓子shell,前後空格,最後一個加;號
[] 邏輯判斷,不支持正則表達式
[[]] 邏輯判斷,支持正則表達式,一般用[]
=~  匹配,字符串不要加"",支持正則表達式 
!= 不等
== 相等,字符串不要加"",支持通配符

關係符運算

數值測試,不支持字符
運算符 說明 全稱
-gt 是否大於 greater than
-ge 是否大於等於 greater than equal
-eq 是否等於 equal
-ne 是否不等於 no equal
-lt 是否小於 less than
-le 是否小於等於 less equal

字符串測試

= 是否等於
> ascii碼是否大於
< 是否小於
!= 是否不等於
=~ 左側字符串是否能夠被右側的pattern匹配,一般用於[[]]中
-z "string" 字符串是否爲空,空爲真,非空爲假
-n "string" 字符串是否不空,不空爲真,空位假

文件測試

-a / -e file :文件存在性測試,存在未真,否則爲假
-b 是否存在且爲塊設備文件
-c 是否存在且爲字符設備文件
-d 是否存在且爲目錄文件
-f 是否存在且爲普通文件
-h / -L :存在且爲鏈接文件
-p 是否存在且爲命名管道文件
-S 是否存在且爲套接字文件

權限測試

-r 是否存在且可讀
-w 是否存在且可寫
-x 是否存在且可執行
-u 是否存在且擁有suid權限
-g 是否存在且擁有sgid權限
-k 是否存在且擁有sticky權限

文件屬性

-s 是否存在且爲非空
-t 文件描述符是否在某終端打開
-N 文件自從上一次被讀取之後是否被修改
-O 當前有效用戶是否爲文件時屬主
-G 當前用戶是否爲文件屬組

雙目測試

file1 -ef file2:1是否是2的硬鏈接
file1 -nt file2:1是否新於file2
file1 -ot file2:1是否舊於file2
-a 並且
-o 或者
! 非

3.字符串

單引號

str='this is a string' 
單引號裏的任何字符都會原樣輸出,單引號裏的變量是無效的
單引號字符串中不能出現單引號,對單引號轉義後也不行

雙引號

str="you name is $name"
雙引號裏可以有變量
雙引號裏可以出現轉義字符

拼接字符串

firstname="zhang"
lastname="hw"
echo $firstname $lastname   輸出:zhanghw

獲取字符串長度

str="abcd"
echo ${#str}     輸出:4 

提取子字符串

str="daxiong is the best girl"
echo ${str:1:4}  1:4 起始字符到終止字符,由0開始

查找子字符串

str="daxiong is the best girl"
echo `expr index "$str" is`

4.數組

只支持一維數組,沒有限定數組大小。數組元素下表從0開始,下表可以是整數或算術表達式,其值應大於或等於0

定義

用括號來定義數組,各個元素間用空格分開,如下:
array_name=(value0 value1 value2)

單獨定義
array_name[0]=value0
array_name[1]=value1

引用

${array_name[index]}
a=${array_name[0]}

${array_name[@}}  
${array_name[*]} @或* 可以獲取數組中的所有元素

獲取數組的長度

a=${#array_name[@]} 取得數組元素的個數 @或*都可以
a=${#array_name[n]} 取得下標爲n的元素的長度

5.shell printf

printf命令用於格式化輸出,printf由POSIX標準所定義,移植性比echo好

printf "hello\n" 輸出字符串,printf不自帶換行,需要在字符串最後添加\n
printf format-string [arguments]
format-string爲雙引號

$ printf "%d %s\n" 1 "abc"
1 ab

格式只指定了一個參數,但多出的參數仍然會按照該格式輸出,format-string 被重用
$ printf %s abc def
abcdef

$ printf "%s\n" abc def
abc
def

$ printf "%s %s %s\n" a b c d e f g h i j
a b c
d e f
g h i
j

如果沒有 arguments,那麼 %s 用NULL代替,%d 用 0 代替
$ printf "%s and %d \n" 
and 0

6.if else 語句

  • if...fi
  • if...else...fi
  • if...elif...else...fi
    最後必須以fi結尾來閉合

if 語句的用法

if [ expression ]
then
    Statement(s) to be executed if expression is true
fi
如果expression返回ture,then後面的語句將會被執行;如果返回false則跳出循環

if..else...fi 語句的用法

if [ expression ]
then
    Statement(s) to be executed if expression is true
else
    Statement(s) to be executed if expression is not true
fi
如果expression返回true則執行then後面的語句,否則執行else後面的語句

if...elif...fi 語句的用法

if [ expression 1 ]
then 
    Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
    Statement(s) to be executed if expression 2 is true
else
    Statement(s) to be executed if no expression is true
fi
哪一個expression 的值爲true,就執行那個expression後面的語句,如果都爲false則執行else後面的語句

7.for循環

for varibale in 列表
do
    command1
    command2
    ...
    conmmandN
done
列表是一組數值(數值、字符串等)組成的序列,每個值通過空格分格。每循環一次,就將列表中的下一個值賦給變量
in 列表是可選的,如果不用它,for循環使用命令行的位置參數

seq 列表的產生
wait 

8.while循環

  • while循環用於不斷執行一系列命令,也用於從輸入文件中讀取數據;命令通常爲測試條件

    while command
    do
    Statement(s) to be executed if command is true
    done

: 代表true的意思

9.until循環

  • 直到型循環,當執行結果爲true時才跳出循環。

    until command
    do
    Statement(s) to be executed until command is true
    done

10.continue

跳過本次循環
> break [N] 直接結束第N層的本輪循環,而直接進入下一輪判斷,最內層爲第1層,默認值爲1
    while command1 
    do
        if command2 
        then
            continue
        fi
    done

11.break

跳出整個循環
break [N] 提前結束第N層循環,最內層爲第一層
while command1
do
    if command2 
    then
        break
    fi
done

12.shift

shift [n]
將參量列表list左移指定次數,缺省爲左移一次。列表list一旦被移動,最左端的那個參數就從列表中刪除。

#!/bin/bash
#step through all the positional parameters
until [ -z "$1" ] 
do
    echo "$1"
    shift
done
echo

13.select

select variable in list 
    do 
        循環體命令
    done

select 循環主要用於創建菜單,按數字順序排列的菜單項將顯示在
標準錯誤上,並顯示 PS3 提示符,等待用戶輸入
用戶輸入菜單列表中的某個數字,執行相應的命令
用戶輸入被保存在內置變量 REPLY 中

select 是個無限循環,因此要記住用 break 命令退出循環,或用
exit 命令終止腳本。也可以按 ctrl+c 退出循環
select 經常和 case 聯合使用
與 for 循環類似,可以省略 in list,此時使用位置參量

14.while特殊用法

while read line
do
    循環體
done < /path/from/somefile

依次讀取/path/from/somelife 文件中的每一行,且將行賦值給變量line

15.case...esac

  • case...esca 是一種多分支選擇結構
  • case語句匹配一個值或一個模式,如果匹配成功,執行相匹配的命令。

    case VALUE in
    mode1)
    command 1
    command 2
    command 3
    ;;
    mode2)
    command1
    command2
    command3
    ;;
    esac
    取值後面必須爲關鍵字in,每一模式必須以右括號結束。取值可以爲變量或常數。
    ;; 與其他語言中的break 類似,意思是跳到整個case語句的最後。

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