shell程式設計進階
函式
定義
語法一:
function f_name {
… 函式體…
}
語法二:
function f_name ) () {
… 函式體…
}
語法三:
f_name (){
… 函式體…
}
函式和shell 程式比較相似,區別在於:
- Shell 程式在子Shell 中執行
- 而 而Shell 函式在當前Shell 中執行。因此在當前Shell 中,函式可以
對 對shell
函式使用相關細節
- 函式要先定義後呼叫,定義程式碼在呼叫之前
- 父程序無法呼叫子程序的指令碼;在指令碼2中執行指令碼一,指令碼一中定義了一個函式,指令碼二是無法使用的;如果想要指令碼2使用可在指令碼1中使用source執行
test2.sh
fun1(){
echo 'this is sun1'
}
test1.sh
#!/bin/bash
bash test2.sh
fun1
#報錯
test1.sh
#!/bin/bash
source test2.sh #在同一shell中執行
fun1
#正常輸出
- 一旦函式檔案載入shell,就可以在命令列或指令碼中呼叫函式。可以使用set 命令檢視所有定義的函式,其輸出列表包括已經載入shell 的所有函式
- 變數作用域類似js,區域性變數用local宣告
- 若要改動函式,首先用unset命令從shell中刪除函式。改動完畢後,再重新載入此檔案
- 檔名可任意選取,但最好與相關任務有某種聯絡。例如:functions.main
- 如果函式中有區域性變數,如果其名稱同本地變數,使
用區域性變數。
返回值
(1) 使用echo 等命令 進行輸出
(2) 函式體中呼叫命令的輸出結果
函式的退出狀態碼:
(1) 預設取決於函式中執行的最後一條命令的退出狀態碼
(2) 自定義退出狀態碼, 其格式為:
- return 從函式中返回,用最後狀態命令決定返回值
- return 0 無錯誤返回。
- return 1-255 有錯誤 返回
環境函式
匯出為環境函式:export -f function_name
檢視環境函式:export -f 或者declare -fx (declare -f普通函式)
. functions.main
func1
export -f func1
declare -f
export -f quote
export -f
fork 炸彈
:(){:|:&};:
bomb(){bomb|bomb&};:
指令碼實現
!/bin/bash
./
或者bash
陣列
變數:儲存單個元素的記憶體空間
陣列:儲存多個元素的連續的記憶體空間,相當於多個變數的集合
bash4.0 版本之後開始支援關聯陣列(bash –version | rpm -qi bash)
bash 的陣列支援稀疏格式(索引不連續)
宣告陣列
- declare -a ARRAY_NAME
- declare -A ARRAY_NAME: (關聯陣列)
陣列賦值
(1) 一次只賦值一個元素;
ARRAY_NAME[INDEX]=VALUE
weekdays[0]="Sunday"
weekdays[4]="Thursday"
(2) 一次賦值全部元素:
ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
arr1=({1..10})
arr2=(/var/log/*.log)
arr3=({a,b,c}.{txt,log})
(3) 只賦值特定元素:
ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
(4) 互動式陣列值對賦值
read -a ARRAY
引用陣列
引用陣列元素:${ARRAY_NAME[INDEX]}
注意:省略[INDEX] 表示引用下標為0 的元素
陣列的長度( 陣列中元素的個數):
${#ARRAY_NAME[*]}
${#ARRAY_NAME[@]}
示例:生成10 個隨機數保存於陣列中,並找出其最大值和最小值
#!/bin/bash
declare -a rand
declare -i max=0
declare –i min=32767
for i in {0..9}; do
rand[$i]=$RANDOM
echo ${rand[$i]}
[ ${rand[$i]} -gt $max ] && max=${rand[$i]}
[ ${rand[$i]} -lt $min ] && min=${rand[$i]}
done
echo "Max: $max Min:$min"
編寫指令碼,定義一個數組,陣列中的元素是/var/log 目錄下所有以.log 結尾的檔案;要統計其下標為偶數的檔案中的行數之和
#!/bin/bash
#
declare -a files
files=(/var/log/*.log)
declare -i lines=0
for i in $(seq 0 $[${#files[*]}-1]); do
if [ $[$i%2] -eq 0 ];then
let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1)
fi
done
echo "Lines: $lines."
陣列資料處理
引用陣列中的元素:
所有元素:ARRAY[@], {ARRAY[*]}
陣列切片:${ARRAY[@]:offset:number}
- offset: 要跳過的元素個數
- number: 要取出的元素個數
取偏移量之後的所有元素${ARRAY[@]:offset}
向陣列中追加元素:ARRAY[${#ARRAY[*]}]
刪除陣列中的某元素:導致稀疏格式unset ARRAY[INDEX]
關聯陣列:
declare -A ARRAY_NAME 注意:必須先宣告,再呼叫
ARRAY_NAME=([idx_name1]=’val1’ [idx_name2]=’val2‘…)
字串字串切片
${#var}: 返回字串變數var 的長度
var:offset:返回字符串變量var中從第offset個字符後(不包括第offset個字符)的字符開始,到最後的部分,offset的的取值在0到到 {#var}-1 之間(bash4.2 後,允許為負值)
${var:offset:number}:返回字串變數var中從第offset個字元後(不包括第offset 個字元)的字元開始 ,長度為number 的部分
${var: -length} :取字串的最右側幾個字元
==注意:冒號後必須有一空白字元==
${var:offset:-length} :從最左側跳過offset字元,一直取到字串的 最 右側lengh 個字元之前
${var: -length:-offset}:從最右側向左取到length個字元開始,再向右取到距離最右側offset 個字元之間的內容
基於模式取子串:
${var#*word} :其中word 可以是指定的任意字元
功能:自左而右,查詢var 變數所儲存的字串中,第一次出現的word, 刪除字串開頭至第一次出現word字元之間的所有字元${var##*word}:同上,不同的是,刪除的是字串開頭至最後一次由word 指定的字元之間的 所有內容
示例:
file="var/log/messages“
${file#*/}: log/messages
${file##*/}: messages
${var%word*} :其中word 可以是指定的任意字元;
功能:自右而左,查詢var 變數所儲存的字串中,第一次出現的word,刪除字串最後一個字元向左至第一次出現word字元之間的所有字元;
file="/var/log/messages"
${file%/*}: /var/log
${var%%word*} :同上,只不過刪除字串最右側的字元向左至最後一次出現word 字元之間的所有字元;
示例:
url=http://www.magedu.com:80
${url##*:} 80
${url%%:*} http
查詢替換:
${var/pattern/substi}:查詢var所表示的字串中,第一次被pattern 所匹配到的字串,以substi 替換之
${var//pattern/substi}:查詢var所表示的字串中,所有能被pattern 所匹配到的字串,以substi 替換之
${var/#pattern/substi} :查詢var 所表示的字串中,行首被pattern 所匹配到的字串,以substi 替換之
${var/%pattern/substi} :查詢var所表示的字串中,行尾被pattern 所匹配到的字串,以substi
查詢並刪除:
${var/pattern} :查詢var 所表示的字串中,刪除第一次被pattern 所匹配到的字串
${var//pattern} :所有
${var/#pattern} :行首
${var/%pattern} :行尾
字元大小寫轉換:
${var^^} :把var 中的所有小寫字母轉換為大寫
${var,,} :把var 中的所有大寫字母轉換為小寫
變數賦值
${var:-value} :如果var為空或未設定,那麼返回value;否則返回var 的值,可省略:
${var:+value} :如果var 不空,則返回value ,否則返回空值
${var:=value} :如果var 為空或未設定,那麼返回value ,並將value 賦值給var ;否則返回var 的值
${var:?error_info}:如果var為空或未設定,那麼在當前終端列印error_info ;否則返回var
綜合例項
str=$(echo {a..z}|tr -d ' ')
echo ${#str}
26
echo ${str:3}
defghijklmnopqrstuvwxyz
echo ${str:3:6}
defghi
echo ${str: -3}#注意空格
xyz
user=$(getent passwd root)
echo ${user#*root} #刪除第一次出現root的
:x:0:0:root:/root:/bin/bash
echo ${user##*root}#刪除所有出現的root
:/bin/bash
echo ${user%root*} #刪除最後一個root以及其後的字元
root:x:0:0:root:/
user1=super$user
echo $user1
superroot:x:0:0:root:/root:/bin/bash
echo ${user1%%root*} #貪婪模式,刪除第一個root以及其後的字元
super
url='http://www.baidu.com:80'
echo ${url%%:*} 從右向左匹配到最後一個:後刪除
http
echo ${url##*:} 從左向右匹配到最後一個:後刪除
80
# 搜尋替換
user=$(getent passwd root)
echo ${user/root/lee} #只替換第一個
lee:x:0:0:root:/root:/bin/bash
echo ${user//root/lee} #全域性替換
lee:x:0:0:lee:/lee:/bin/bash
echo ${user/#root/lee}# 匹配root開頭的行(#錨定行首)
lee:x:0:0:root:/root:/bin/bash
echo ${user/%bash/lee}# 匹配bash結尾的行(%錨定詞尾)
root:x:0:0:root:/root:/bin/lee
#搜尋刪除(用空替代)
user=$(getent passwd root)
echo ${user/root/} #只替換第一個
:x:0:0:root:/root:/bin/bash
echo ${user//root/} #全域性替換
:x:0:0::/:/bin/bash
echo ${user/#root/}# 匹配root開頭的行(#錨定行首)
:x:0:0:root:/root:/bin/bash
echo ${user/%bash/}# 匹配bash結尾的行(%錨定詞尾)
root:x:0:0:root:/root:/bin/
#轉換成大寫
echo ${user^^}
ROOT:X:0:0:ROOT:/ROOT:/BIN/BASH
user1=${user^^}
echo $user1
ROOT:X:0:0:ROOT:/ROOT:/BIN/BASH
echo ${user1,,}
root:x:0:0:root:/root:/bin/bash
指定變數型別
Shell 變數一般是無型別的,但是bashShell提供了declare和typeset,兩個命令等價
declare [ 選項] 變數名
options | complications |
---|---|
-r | 將變數設定為只讀屬性 |
-i | 將變數定義為整型數 |
-a | 將變數定義為陣列 |
-A | 將變數定義為關聯陣列 |
-f | 顯示此指令碼前定義過的所有函式名及其內容 |
-F | 僅顯示此指令碼前定義過的所有函式名 |
-x | 將變數宣告為環境變數 |
-l | 將變數值轉為小寫字母 declare –l var=UPPER |
-u | 將變數值轉為大寫字母 declare –u var=lower |
declare -xf fun1定義環境函式
declare -l lower=ASFDF
echo $lower
asdfdf
eval 命令將會首先掃描命令列進行所有的置換,然後再執行該命令。該命令適用於那些一次掃描無法實現其功能的變數.該命令對變數進行兩次掃描
[root@server ~]# CMD=whoami
[root@server ~]# echo $CMD
whoami
[root@server ~]# eval $CMD
root
[root@server ~]# n=10
[root@server ~]# echo {0..$n}
{0..10}
[root@server ~]# eval echo {0..$n}
0 1 2 3 4 5 6 7 8 9 10
間接變數引用
如果第一個變數的值是第二個變數的名字,從第一個變數引
用第二個變數的值就稱為間接變數引用
variable1=variable2
variable2=value
variable1 的值是variable2,而variable2又是變數名,variable2的值為value,間接變數引用是指通過variable1獲得變數值value
bash Shell 提供了兩種格式實現間接變數引用
- eval tempvar=$$variable1
- tempvar=${!variable1}
例項
[root@server ~]# N=NAME
[root@server ~]# NAME=wangxiaochun
[root@server ~]# N1=${!N}
[root@server ~]# echo $N1
wangxiaochun
[root@server ~]# eval N2=\$$N
[root@server ~]# echo $N2
wangxiaochun
mktemp 命令:建立的臨時檔案可避免衝突
mktemp [OPTION]… [TEMPLATE]
TEMPLATE: filename.XXX
X 至少要出現三個
OPTION: :
- -d: 建立臨時目錄
- -p DIR 或–tmpdir=DIR :指明臨時檔案所存放目錄位置
示例:
#mktemp /tmp/test.XXX
#tmpdir=`mktemp –d /tmp/testdir.XXX`
#mktemp --tmpdir=/testdir test.XXXXXX
安裝複製檔案
install 命令:
install [OPTION]… [-T] SOURCE DEST 單檔案
install [OPTION]… SOURCE… DIRECTORY
install [OPTION]… -t DIRECTORY SOURCE…
install [OPTION]… -d DIRECTORY… 建立空目錄
選項:
-m MODE ,預設755
-o OWNER
-g GROUP
示例:
install -m 700 -o wang -g admins file1 file2
install –m –d /testdir/installdir