1. 程式人生 > >shell程式設計進階

shell程式設計進階

函式

定義

語法一:

function f_name {
… 函式體…
}

語法二:

function f_name ) () {
… 函式體…
}

 語法三:

f_name (){
… 函式體…
}

函式和shell 程式比較相似,區別在於:

  • Shell 程式在子Shell 中執行
  • 而 而Shell 函式在當前Shell 中執行。因此在當前Shell 中,函式可以
    對 對shell

函式使用相關細節

  1. 函式要先定義後呼叫,定義程式碼在呼叫之前
  2. 父程序無法呼叫子程序的指令碼;在指令碼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

#正常輸出
  1. 一旦函式檔案載入shell,就可以在命令列或指令碼中呼叫函式。可以使用set 命令檢視所有定義的函式,其輸出列表包括已經載入shell 的所有函式
  2. 變數作用域類似js,區域性變數用local宣告
  3. 若要改動函式,首先用unset命令從shell中刪除函式。改動完畢後,再重新載入此檔案
  4. 檔名可任意選取,但最好與相關任務有某種聯絡。例如:functions.main
  5. 如果函式中有區域性變數,如果其名稱同本地變數,使
    用區域性變數。

返回值

(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

./0|./0&
或者bash 0|bash0&

陣列

變數:儲存單個元素的記憶體空間

陣列:儲存多個元素的連續的記憶體空間,相當於多個變數的集合

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:varoffsetoffsetoffset0{#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