Shell腳本編程筆記


title: Shell 編程
tags:shell

- Shell

categories:編程

- Linux


[TOC]數組

注意: 不要將腳本命名爲test,由於test是一個內置的應用程序bash

第一個shell腳本

#!/bin/bash
# File: hello.sh
echo "Hello World !"
bovenson@ThinkCentre:~/Git/neu-ip-gateway-manager$ bash hello.sh 
Hello World!

變量

定義ssh

v="This is a variable."

注意編程語言

  • 變量名和等號之間不能有空格
  • 首個字符必須爲字母(a-z,A-Z)
  • 中間不能有空格,可使用下劃線(_)
  • 不能使用標點符號
  • 不能使用bash裏的關鍵字(可用help命令查看保留關鍵字)
  • 已定義的變量,能夠被從新定義

使用函數

使用一個定義過的變量,只要在變量名前面加美圓符號便可工具

#!/bin/bash
# File: hello.sh

v="This is a variable."

echo $v
echo ${v}    # 變量名外面的花括號是可選的,加不加都行,加花括號是爲了幫助解釋器識別變量的邊界
bovenson@ThinkCentre:~/Tmp$ bash hello.sh 
This is a variable.
This is a variable.
bovenson@ThinkCentre:~/Tmp$

變量名外面的花括號是可選的,加不加都行,加花括號是爲了幫助解釋器識別變量的邊界, 推薦給全部變量加上花括號,這是個好的編程習慣, 好比下面這種狀況:oop

for skill in Ada Coffe Action Java; do
    echo "I am good at ${skill}Script"
done

只讀變量測試

使用 readonly 命令能夠將變量定義爲只讀變量,只讀變量的值不能被改變。

#!/bin/bash
# File: hello.sh

my_name="szk"
readonly my_name
my_name="bovenson"
bovenson@ThinkCentre:~/Tmp$ bash hello.sh 
hello.sh:行6: my_name: 只讀變量
bovenson@ThinkCentre:~/Tmp$

刪除變量

unset variable_name

注意:

  • 變量被刪除後不能再次使用
  • unset命令不能刪除只讀變量

變量類型

  • 局部變量: 局部變量在腳本或命令中定義,僅在當前shell實例中有效,其餘shell啓動的程序不能訪問局部變量
  • 環境變量: 全部的程序,包括shell啓動的程序,都能訪問環境變量,有些程序須要環境變量來保證其正常運行。必要的時候shell腳本也能夠定義環境變量
  • shell變量: shell變量是由shell程序設置的特殊變量。shell變量中有一部分是環境變量,有一部分是局部變量,這些變量保證了shell的正常運行

字符串

字符串是shell編程中最經常使用最有用的數據類型(除了數字和字符串,也沒啥其它類型好用了),字符串能夠用單引號,也能夠用雙引號,也能夠不用引號。單雙引號的區別跟PHP相似。

單引號

str='this is a string'

單引號字符串的限制:

  • 單引號裏的任何字符都會原樣輸出,單引號字符串中的變量是無效的
  • 單引號字串中不能出現單引號(對單引號使用轉義符後也不行)

雙引號

my_name='szk'
str="Hello, I know your are \"$my_name\"! \n"

雙引號的優勢:

  • 雙引號裏能夠有變量
  • 雙引號裏能夠出現轉義字符

拼接字符串

#!/bin/bash
# File: hello.sh

my_name="szk"
greeting="hello, "$my_name" !"
greeting_1="hello, ${my_name} !"
echo $greeting $greeting_1
bovenson@ThinkCentre:~/Tmp$ bash hello.sh 
hello, szk ! hello, szk !
bovenson@ThinkCentre:~/Tmp$

獲取字符串長度

#!/bin/bash
# File: hello.sh

my_name="szk"
echo ${#my_name}
bovenson@ThinkCentre:~/Tmp$ bash hello.sh 
3

提取子字符串

#!/bin/bash
# File: hello.sh

slogon="One World, One Dream!"
echo ${slogon:4:5}    # 這裏4是開始下標, 5是截取長度
bovenson@ThinkCentre:~/Tmp$ bash hello.sh 
World

查找字符串中字符位置

#!/bin/bash
# File: hello.sh

slogon="One World, One Dream!"

index=`expr index "$slogon" W`    # 查找W字符
echo ${index}
index=`expr index "$slogon" Dra` # 查找字符D, r, a中的一個
echo ${index}
bovenson@ThinkCentre:~/Tmp$ bash hello.sh 
5
7

字符串截取

假設有變量 var=http://www.aaa.com/123.htm

方法一

# # 號截取,刪除左邊字符,保留右邊字符
echo ${var#*//}
# 其中 var 是變量名,# 號是運算符,*// 表示從左邊開始刪除第一個 // 號及左邊的全部字符
# 即刪除 http://
# 結果是 :www.aaa.com/123.htm

方法二

# ## 號截取,刪除左邊字符,保留右邊字符。
echo ${var##*/}
# ##*/ 表示從左邊開始刪除最後(最右邊)一個 / 號及左邊的全部字符
# 即刪除 http://www.aaa.com/
# 結果是 123.htm

方法三

# %號截取,刪除右邊字符,保留左邊字符
 echo ${var%/*}
 # %/* 表示從右邊開始,刪除第一個 / 號及右邊的字符
 # 結果是:http://www.aaa.com

方法四

# %% 號截取,刪除右邊字符,保留左邊字符
echo ${var%%/*}
# %%/* 表示從右邊開始,刪除最後(最左邊)一個 / 號及右邊的字符
# 結果是:http:

方法五

# 從左邊第幾個字符開始,及字符的個數
echo ${var:0:5}
# 其中的 0 表示左邊第一個字符開始,5 表示字符的總個數。
# 結果是:http:

方法六

# 從左邊第幾個字符開始,一直到結束
echo ${var:7}
# 其中的 7 表示左邊第8個字符開始,一直到結束
# 結果是 :www.aaa.com/123.htm

方法七

# 從右邊第幾個字符開始,及字符的個數
echo ${var:0-7:3}
# 其中的 0-7 表示右邊算起第七個字符開始,3 表示字符的個數。
# 結果是:123

方法八

# 從右邊第幾個字符開始,一直到結束
echo ${var:0-7}
# 表示從右邊第七個字符開始,一直到結束。
# 結果是:123.htm

注:

  • 左邊的第一個字符是用 0 表示,右邊的第一個字符用 0-1 表示

數組

  • bash支持一維數組(不支持多維數組)
  • 數組元素的下標由0開始編號
  • 獲取數組中的元素要利用下標,下標能夠是整數或算術表達式,其值應大於或等於0
  • 能夠不使用連續的下標,並且下標的範圍沒有限制。

定義數組

在Shell中,用括號來表示數組,數組元素用"空格"符號分割開:

數組名=(值1 值2 ... 值n)

例如:array_name=(value0 value1 value2 value3)

或者:

array_name=(
value0
value1
value2
value3
)

還能夠單獨定義數組的各個份量:

array_name[0]=value0
array_name[1]=value1
.
.
.
array_name[n]=valuen

讀取數組

讀取數組元素值的通常格式是:

${數組名[下標]}

例如:

valuen=${array_name[n]}

使用@符號能夠獲取數組中的全部元素,例如:

echo ${array_name[@]}

#!/bin/bash
# File: hello.sh

slogon=("One" "World" "," "One" "Dream!")
echo ${slogon[0]}
echo ${slogon[1]}
echo ${slogon[@]}
bovenson@ThinkCentre:~/Tmp$ bash hello.sh 
One
World
One World , One Dream!
bovenson@ThinkCentre:~/Tmp$

獲取數組長度

#!/bin/bash
# File: hello.sh

slogon=("One" "World" "," "One" "Dream!")
# 獲取數組長度的方法與獲取字符串長度的方法相同
echo ${#slogon[@]}
echo ${#slogon[*]}
bovenson@ThinkCentre:~/Tmp$ bash hello.sh 
5
5

註釋

  • 以"#"開頭的行就是註釋,會被解釋器忽略
  • sh裏沒有多行註釋,只能每一行加一個#號

示例:

#--------------------------------------------
# 這是一個註釋
# author:菜鳥教程
# site:www.runoob.com
# slogan:學的不只是技術,更是夢想!
#--------------------------------------------
##### 用戶配置區 開始 #####
#
#
# 這裏能夠添加腳本描述信息
# 
#
##### 用戶配置區 結束  #####

每一行加個#符號太費力了,能夠把這一段要註釋的代碼用一對花括號括起來,定義成一個函數,沒有地方調用這個函數,這塊代碼就不會執行,達到了和註釋同樣的效果.

參數

位置參數

咱們能夠在執行 Shell 腳本時,向腳本傳遞參數,腳本內獲取參數的格式爲:$nn 表明一個數字,1 爲執行腳本的第一個參數,2 爲執行腳本的第二個參數,以此類推……

位置參數包括命令名和命令行參數.在shell腳本中, 按照它們在命令行上的位置來引用它們(如命令command a b c 中參數a,b,c的位置 ). 不能經過賦值語句改變位置參數的值.

bash的內置命令set能夠修改除調用程序名(命令名)之外的任意位置參數, 可是在tcsh中, set內置命令不能改變位置參數的值

在腳本中使用 $0 $1 來獲取位置參數
#!/bin/bash
# File: hello.sh

echo "Shell 傳遞參數實例!";
echo "執行的文件名:$0";
echo "第一個參數爲:$1";
echo "第二個參數爲:$2";
echo "第三個參數爲:$3";
bovenson@ThinkCentre:~/Tmp$ bash hello.sh v1 v2 v3 v4 v5 v6 v7
Shell 傳遞參數實例!
執行的文件名:hello.sh
第一個參數爲:v1
第二個參數爲:v2
第三個參數爲:v3
bovenson@ThinkCentre:~/Tmp$

幾個特殊字符用來處理參數

字符 說明
$# 傳遞到腳本的參數個數
$* 以一個單字符串顯示全部向腳本傳遞的參數。如$*"括起來的狀況、以$1 $2$n的形式輸出全部參數。
$$ 腳本運行的當前進程ID號
$! 後臺運行的最後一個進程的ID號
$@ $*相同,可是使用時加引號,並在引號中返回每一個參數。如$@"括起來的狀況、以$1 $2$n 的形式輸出全部參數。
$- 顯示Shell使用的當前選項,與set命令功能相同。
$? 顯示最後命令的退出狀態。0表示沒有錯誤,其餘任何值代表有錯誤。
#!/bin/bash
# File: hello.sh

echo "Shell 傳遞參數實例!";
echo "第一個參數爲:$1";

echo "參數個數爲:$#";
echo "傳遞的參數做爲一個字符串顯示:$*";
bovenson@ThinkCentre:~/Tmp$ bash hello.sh v1 v2 v3 v4 v5 v6 v7
Shell 傳遞參數實例!
第一個參數爲:v1
參數個數爲:7
傳遞的參數做爲一個字符串顯示:v1 v2 v3 v4 v5 v6 v7

$*$@ 區別

  • 相同點:都是引用全部參數。
  • 不一樣點:只有在雙引號中體現出來。假設在腳本運行時寫了三個參數 一、二、3,,則 " * " 等價於 "1 2 3"(傳遞了一個參數),而 "@" 等價於 "1" "2" "3"(傳遞了三個參數)。

基本運算符

原生bash不支持簡單的數學運算,可是能夠經過其餘命令來實現,例如 awk 和 expr,expr 最經常使用。

expr 是一款表達式計算工具,使用它能完成表達式的求值操做。例如,兩個數相加(注意使用的是反引號 ` 而不是單引號 '):

#!/bin/bash

val=`expr 2 + 2`
echo "兩數之和爲 : $val"
  • 表達式和運算符之間要有空格,例如 2+2 是不對的,必須寫成 2 + 2,這與咱們熟悉的大多數編程語言不同。
  • 完整的表達式要被反引號包含,注意這個字符不是經常使用的單引號,在 Esc 鍵下邊。

算術運算符

運算符 說明 舉例
+ 加法 `expr $a + $b` 結果爲 30
- 減法 `expr $a - $b` 結果爲 -10
* 乘法 `expr $a \* $b` 結果爲 200
/ 除法 `expr $b / \$a` 結果爲 2
% 取餘 `expr $b % $a` 結果爲 0
= 賦值 a=$b 將把變量 b 的值賦給 a
== 相等。用於比較兩個數字,相同則返回 true [ $a == $b ] 返回 false
!= 不相等。用於比較兩個數字,不相同則返回 true [ $a != \$b ] 返回 true

注意:

  • 條件表達式要放在方括號之間,而且要有空格,例如: [$a==$b] 是錯誤的,必須寫成 [ $a == $b ]
  • 乘號(*)前邊必須加反斜槓()才能實現乘法運算

關係運算符

  • 關係運算符只支持數字,不支持字符串,除非字符串的值是數字
運算符 說明
-eq 檢測兩個數是否相等,相等返回 true
-ne 檢測兩個數是否相等,不相等返回 true
-gt 檢測左邊的數是否大於右邊的,若是是,則返回 true
-lt 檢測左邊的數是否小於右邊的,若是是,則返回 true
-ge 檢測左邊的數是否大於等於右邊的,若是是,則返回 true
-le 檢測左邊的數是否小於等於右邊的,若是是,則返回 true

布爾運算符

運算符 說明
! 非運算,表達式爲 true 則返回 false,不然返回 true
-o 或運算,有一個表達式爲 true 則返回 true
-a 與運算,兩個表達式都爲 true 才返回 true

邏輯運算符

運算符 說明
&& 邏輯的 AND
\ \ 邏輯的 OR

字符串運算符

運算符 說明
= 檢測兩個字符串是否相等,相等返回 true
!= 檢測兩個字符串是否相等,不相等返回 true
-z 檢測字符串長度是否爲0,爲0返回 true
-n 檢測字符串長度是否爲0,不爲0返回 true
str 檢測字符串是否爲空,不爲空返回 true, 如 [ $a ]

文件測試運算符

文件測試運算符用於檢測 Unix 文件的各類屬性

操做符 說明 舉例
-b file 檢測文件是不是塊設備文件,若是是,則返回 true。 [ -b $file ] 返回 false。
-c file 檢測文件是不是字符設備文件,若是是,則返回 true。 [ -c $file ] 返回 false。
-d file 檢測文件是不是目錄,若是是,則返回 true。 [ -d $file ] 返回 false。
-f file 檢測文件是不是普通文件(既不是目錄,也不是設備文件),若是是,則返回 true。 [ -f $file ] 返回 true。
-g file 檢測文件是否設置了 SGID 位,若是是,則返回 true。 [ -g $file ] 返回 false。
-k file 檢測文件是否設置了粘着位(Sticky Bit),若是是,則返回 true。 [ -k $file ] 返回 false。
-p file 檢測文件是不是有名管道,若是是,則返回 true。 [ -p $file ] 返回 false。
-u file 檢測文件是否設置了 SUID 位,若是是,則返回 true。 [ -u $file ] 返回 false。
-r file 檢測文件是否可讀,若是是,則返回 true。 [ -r $file ] 返回 true。
-w file 檢測文件是否可寫,若是是,則返回 true。 [ -w $file ] 返回 true。
-x file 檢測文件是否可執行,若是是,則返回 true。 [ -x $file ] 返回 true。
-s file 檢測文件是否爲空(文件大小是否大於0),不爲空返回 true。 [ -s $file ] 返回 true。
-e file 檢測文件(包括目錄)是否存在,若是是,則返回 true。 [ -e $file ] 返回 true。

控制結構

if...then

if test-command
then
        comands
fi
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi

if else

if condition
then
    command1 
    command2
    ...
    commandN
else
    command
fi

if else-if else

if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi

for 循環

for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done
for var in item1 item2 ... itemN; do command1; command2… done;
# 示例 1
for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done
# 輸出
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

# 示例 2
for str in 'This is a string'
do
    echo $str
done
# 輸出
This is a string

while 語句

while condition
do
    command
done
# 示例 1
#!/bin/sh
int=1
while(( $int<=5 ))
do
        echo $int
        let "int++"
done
# 輸出
1
2
3
4
5

# 示例 2
echo '按下 <CTRL-D> 退出'
echo -n '輸入你最喜歡的電影名: '
while read FILM
do
    echo "是的!$FILM 是一部好電影"
done

無限循環

while :
do
    command
done

# 或者
while true
do
    command
done

# 或者
for (( ; ; ))

until 循環

until condition
do
    command
done

# 條件可爲任意測試條件,測試發生在循環末尾,所以循環至少執行一次—請注意這一點

case

case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac

# case的語法和C family語言差異很大,它須要一個esac(就是case反過來)做爲結束標記
# 每一個case分支用右圓括號,用兩個分號表示break。

跳出循環

在循環過程當中,有時候須要在未達到循環結束條件時強制跳出循環,Shell使用兩個命令來實現該功能:break和continue。

函數

shell中函數的定義格式以下:

[ function ] funname [()]
{
    action;
    [return int;]
}
  • 能夠帶function fun() 定義,也能夠直接fun() 定義,不帶任何參數
  • 參數返回,能夠顯示加:return 返回,若是不加,將以最後一條命令運行結果,做爲返回值。 return後跟數值n(0-255)
# 示例 1
demoFun(){
    echo "這是個人第一個 shell 函數!"
}
echo "-----函數開始執行-----"
demoFun
echo "-----函數執行完畢-----"

# 示例 2
funWithReturn(){
    echo "這個函數會對輸入的兩個數字進行相加運算..."
    echo "輸入第一個數字: "
    read aNum
    echo "輸入第二個數字: "
    read anotherNum
    echo "兩個數字分別爲 $aNum 和 $anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn
echo "輸入的兩個數字之和爲 $? !"

輸入/輸出重定向

命令 說明
command > file 將輸出重定向到 file。
command < file 將輸入重定向到 file。
command >> file 將輸出以追加的方式重定向到 file。
n > file 將文件描述符爲 n 的文件重定向到 file。
n >> file 將文件描述符爲 n 的文件以追加的方式重定向到 file。
n >& m 將輸出文件 m 和 n 合併。
n <& m 將輸入文件 m 和 n 合併。
<< tag 將開始標記 tag 和結束標記 tag 之間的內容做爲輸入。

須要注意的是文件描述符 0 一般是標準輸入(STDIN),1 是標準輸出(STDOUT),2 是標準錯誤輸出(STDERR)。

參考

相關文章
相關標籤/搜索