1. 程式人生 > >shell 編程 之 小技巧

shell 編程 之 小技巧

select shift 信號捕捉

1 概述

本文將通過介紹shell腳本編程過程中常用的一些命令,來提高shell腳本編程的靈活性,以及高效實現編程結果

分別介紹了以下10個工具

shift,select,信號捕捉,數組,字符串處理,定義變量,eval,間接變量引用,mktemp,install

2 shift 控制循環

shift [n]

n 用於將參量列表list 左移指定次數,缺省為左移一次。

參量列表list 一旦被移動,最左端的那個參數就從列表中刪除。while 循環遍歷位置參量列表時,常用到shift

運行 ./Tshift.sh a b c d 可以看到每次循環$1的值都不一樣,而且依次向左移動,參數的個數也不一樣

腳本如下:

until  (($#==0));do
echo "\$1 is $1"
echo "var num \$# is $#"
shift
done

3 select循環與菜單

語法如下

select variable in list

do

循環體命令

done

select 循環主要用於創建菜單,按數字順序排列的菜單項將顯示在標準錯誤上,並顯示PS3 提示符,等待用戶輸入

用戶輸入菜單列表中的某個數字,執行相應的命令

用戶輸入被保存在內置變量REPLY 中

select 是個無限循環,因此要記住用break 命令退出循環,或用exit 命令終止腳本。也可以按ctrl+c 退出循環

select 經常和case 聯合使用

與for 循環類似,可以省略in list,此時使用位置參量

腳本如下

註意,如果把註釋的#select menu in [email protected]這句話啟用,就註釋掉菜單那一句,並且執行的時候,要帶上參數。

PS3="please input your choice: "
select menu in well job hello world bye;
#select menu in [email protected];
do
case $menu in
well)
echo "You have done well"
;;
job)
echo "Nice job"
;;
hello)
echo "hello world"
;;
world)
echo "work hard"
;;
bye)
echo "See U tomorrow"
break
;;
*)
echo "Please re-input"
;;
esac
done

4 信號捕捉

trap ‘觸發指令‘ 信號:自定義進程收到系統發出的指定信號後,將執行觸發指令,而不會執行原操作

trap ‘‘ 信號:忽略信號的操作

trap ‘-‘ 信號:恢復原信號的操作

trap -p:列出自定義信號操作

通過執行以下的腳本可以看出效果,ctrl + c 操作時sigint信號

SIGKILL 這個信號不能被捕捉,即-9捕捉不了

測試

當第一個循環的時候,執行kill -2 pid,此時是2信號被忽略,按ctrl+c,腳本不會結束

進入第二個循環前,已經恢復了2的默認信號

在第二個循環的時候,按ctrl+c,腳本結束運行,退出狀態碼是130.被中斷退出。

在第三個循環的時候,自定義了2信號,按ctl+c 或者執行kill -2 pid會打印now catch int 2這句話,同時退出狀態碼是88

trap ‘‘ int
echo "pid is $$"
echo "now 1 diy trap signal"
trap -p
i=1
while [ $i -lt 5 ]
do
sleep 5
echo now i is $i
let i++
done
trap ‘-‘ int
echo "now 2 diy trap signal"
trap -p
j=1
while [ $j -lt 5 ];do
echo j is $j
let j++
sleep 2
done
trap "echo now catch int 2;exit 88" 2
echo "now 3 diy trap signal"
trap -p
m=1
while [ $m -lt 5 ];do
echo m is $m
let m++
sleep 3
done
echo now $0 done

5 數組

數組可以理解成多個變量的集合,當定義的變量含有多個元素,建議用數組,比較方便

變量:存儲單個元素的內存空間

數組:存儲多個元素的連續的內存空間,相當於多個變量的集合

數組名和索引

索引:編號從0開始,屬於數值索引

註意:索引可支持使用自定義的格式,而不僅是數值格式,即為關聯索引,bash4.0版本之後開始支持

bash的數組支持稀疏格式(索引不連續)

聲明數組:

declare -a ARRAY_NAME

declare -A ARRAY_NAME

-a定義的是普通的數值,也叫下標數組,下標數組元素是通過數組下標(數組下標可以是算術表達式,其結果必須是一個整數)來訪問的,但是這種訪問方式在表達某些關聯性很強的數據時會存在限制。

-A定義的是關聯數組,使用任意的字符串作為下標(不必是整數)來訪問數組元素,關聯數組的下標和值稱為鍵值對,它們是一一對應的關系。在關聯數組中,鍵是唯一的,值可以不唯一。

shell 的關聯數組和 shell 的下標數組在定義和使用上完全一樣,只是在索引上有區別。

註意:兩者不可相互轉換,在使用關聯數組之前,需要使用命令 declare -A array 進行顯示聲明。默認數組定義是-a

5.1 數組賦值

數組元素的賦值

註意,如果定義重復名稱的數組,則原來數值的所有值都會被覆蓋

只有一次只賦值一個元素,這個定義方式不會覆蓋掉整個數組,其他三個方式都會覆蓋所有的數組

(1) 一次只賦值一個元素,這個定義方式不會覆蓋掉整個數組

ARRAY_NAME[INDEX]=VALUE

weekdays[0]="Sunday"

weekdays[4]="Thursday"

(2) 一次賦值全部元素

ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)

(3) 只賦值特定元素

ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)

(4) 交互式數組值對賦值

read -a ARRAY,然後輸入參數,用空格隔開,數組定義完成後按enter結束對ARRAY數組的定義

5.2 引用數組

引用數組元素:

${ARRAY_NAME[INDEX]}

註意:省略[INDEX]表示引用下標為0的元素

引用數組所有元素:

${ARRAY_NAME[*]}

${ARRAY_NAME[@]}

數組的長度(數組中元素的個數):

${#ARRAY_NAME[*]}

${#ARRAY_NAME[@]}

刪除數組中的某元素:導致稀疏格式

unset ARRAY[INDEX]

如unset sunny[2]

刪除整個數組:

unset ARRAY

查看所有數組

顯示所有普通數組:declare -a

顯示所有關聯數組:declare -A

5.3數組數據處理

引用數組中的元素:

數組切片:${ARRAY[@]:offset:number}

offset: 要跳過的元素個數

number: 要取出的元素個數

如: declare -a weekday=‘([0]="Sun" [1]="Mon" [2]="Tue" [3]="Wen" [4]="Thu")‘

echo $[weekday[@]:2:2]

結果是Tue Wen

取偏移量之後的所有元素${ARRAY[@]:offset}

向數組中追加元素:

ARRAY[${#ARRAY[*]}]=value

關聯數組:

declare -A ARRAY_NAME ARRAY_NAME=([idx_name1]=‘val1‘ [idx_name2]=‘val2‘...)

5.4 例子

以下兩個例子

ex1 找出10個99以內的隨機數的最大值和最小值

ex2 計算/var/log/*.log下所有下標是偶數的文件的行數的總和

註意ex2 中

files=(/var/log/*.log)

直接給數組分配了值,用來通配符的寫法

#ex1: to find max and min num in ten nums
declare -a rand
declare -i max=0
declare -i min=32767
for i in {0..9} ; do
    rand[$i]=$[$RANDOM%99]
    echo rand[$i]=${rand[$i]}
    [ ${rand[$i]} -gt $max ] && max=${rand[$i]}
    [ ${rand[$i]} -lt $min ] && min=${rand[$i]}
done
echo "MAX:$max min:$min"


#ex2:to sum the lines in /var/log/*.log which subscript is even num
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 "total lines is $lines"

6 字符串處理

6.1 字符串切片

${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個字符之間的內容,先截斷一部分,再取截斷後的前面部分

註意:-length前空格

6.2基於模式取子串

${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

6.3查找替換

${var/pattern/substr}:查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substr替換之

${var//pattern/substr}: 查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substr替換之

${var/#pattern/substr}:查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substr替換之

${var/%pattern/substr}:查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substr替換之

6.4查找並刪除

${var/pattern}:刪除var所表示的字符串中第一次被pattern所匹配到的字符串

${var//pattern}:刪除var所表示的字符串中所有被pattern所匹配到的字符串

${var/#pattern}:刪除var所表示的字符串中所有以pattern為行首所匹配到的字符串

${var/%pattern}:刪除var所表示的字符串中所有以pattern為行尾所匹配到的字符串

6.5字符大小寫轉換

${var^^}:把var中的所有小寫字母轉換為大寫

${var,,}:把var中的所有大寫字母轉換為小寫

6.6變量賦值

變量賦值還有以下的寫法

技術分享

以- 減號為標準來看

-當舊變量沒有賦值時,新變量為賦值的值

-當舊變量已經有賦值了,新變量就和就變量一樣,包括舊變量賦值為空字符串

:-區別就在舊變量為空字符串,新的變量就是賦值的值

其他一樣


以- 減號為標準來看

多了:冒號一般就是強制的賦值,作用於當舊變量已經賦予空字符串的時候

-當舊變量沒有賦值時,新變量為賦值的值

-當舊變量已經有賦值了,新變量就和就變量一樣,包括舊變量賦值為空字符串

:-區別就在舊變量為空字符串,新的變量就是賦值的值

其他一樣


+加號特殊,剛好和-減號大概相反的功能

等號和減號差不多,但是,等號會把舊的變量在沒有設定的情況下,會把舊的變量也一起賦值,同時,當舊變量是空字符的時候,新變量也是空字符,等號就是,當舊變量沒賦值時,新變量為賦值的字段,當舊變量由賦值,等號就是新變量

:=就是舊變量沒有賦值時或者空字符時,新舊變量都是賦值的值,但是舊變量由賦值,新變量為舊變量的值。舊變量不變

?比較特殊,會檢測舊變量是否存在,舊變量沒有賦值,即不存在,就輸出錯,舊變量已經有賦值,新變量就是舊變量的值,舊變量不變,

:?多了冒號,就是當舊變量也為空字符,也輸出錯誤

7 定義變量類型

Shell變量一般是無類型的,但是bash Shell提供了declare和typeset兩個命令用於指定變量的類型,兩個命令是等價的

declare [選項] 變量名

-r 聲明或顯示只讀變量

一旦被賦值為只讀的變量,那麽這個變量將不再被重新賦值或者聲明,也不能被取消設置,必須退出當前shell重新登錄才能取消變量的賦值或定義

-i將變量定義為整型數

-a 將變量定義為數組

-A 將變量定義為關聯數組,下標可以不是數字

-f 顯示已定義的所有函數名及其內容

-F 僅顯示已定義的所有函數名

-x 聲明或顯示環境變量和函數

-l 聲明變量為小寫字母declare –l var=lower

這裏會將var這個變量中原來是大寫的字母全部轉換成小寫字母,小寫字母不變,var實際被賦予的值不包含大寫字母

-u 聲明變量為大寫字母declare –u var=UPPER

這裏會將var這個變量中原來是小寫的字母全部轉換成大寫字母,大寫字母不變,var實際被賦予的值不包含小寫字母

8 eval命令

eval命令將會首先掃描命令行進行所有的置換,然後再執行該命令。該命令適用於那些一次掃描無法實現其功能的變量.該命令對變量進行兩次掃描

示例:

[[email protected]~]# CMD=whoami
[[email protected] ~]# echo $CMD
whoami
[[email protected] ~]# eval $CMD
root
[[email protected]~]# n=10
[[email protected]~]# echo {0..$n}
{0..10}
[[email protected]~]# eval echo {0..$n}
0 1 2 3 4 5 6 7 8 9 10


9 間接變量引用

如果第一個變量的值是第二個變量的名字,從第一個變量引用第二個變量的值就稱為間接變量引用

variable1的值是variable2,而variable2又是變量名,variable2的值為value,間接變量引用是指通過variable1獲得變量值value的行為

variable1=variable2
variable2=value
tempvar=$variable1

此時tempvar這個變量的值是variable2,但是要實現間接引用,使得tempvar的值通過variable1可以被賦值value,就是所謂的間接引用

bash Shell提供了兩種格式實現間接變量引用

花括號裏不能有$號,如果要引用花括號裏的變量,就要用!感嘆號

eval tempvar=\$$variable1
tempvar=${!variable1}

示例:

[[email protected] ~]# N=NAME
[[email protected] ~]# NAME=sunny
[[email protected] ~]# N1=${!N}
[[email protected] ~]# echo $N1
sunny
[[email protected] ~]# eval N2=\$$N
[[email protected] ~]# echo $N2
sunny


10 創建臨時文件

mktemp命令:創建並顯示臨時文件,可避免沖突

mktemp[OPTION]... [TEMPLATE]

TEMPLATE: filename.XXX

X至少要出現三個,為大寫的字母X

OPTION:

-d: 創建臨時目錄

-p DIR或--tmpdir=DIR:指明臨時文件所存放目錄位置

示例:

mktemp/tmp/test.XXX

tmpdir=`mktemp –d /tmp/testdir.XXX`

創建一個臨時目錄,同時把這個目錄的名稱賦值給tmpdir這個變量

mktemp --tmpdir=/testdir test.XXXXXX

11 安裝復制文件

install命令的作用是安裝或升級軟件或備份數據,它的使用權限是所有用戶。

install命令和cp命令類似,都可以將文件/目錄拷貝到指定的地點。但是,install允許你控制目標文件的屬性。

install在拷貝的同時制定新生成文件的屬性,如制定rwx或者所屬組或者所有者的屬性

install通常用於程序的makefile,使用它來將程序拷貝到目標(安裝)目錄。

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

-d 創建新的目錄

更多選項查看鏈接:http://man.linuxde.net/install

示例:

install -m 700 -o wang -g admins srcfile desfile
install –m 766 –d /testdir/installdir

12 總結

編寫腳本的時候,可以借助以上10個工具在來提高編程的效率。

本文出自 “自學linux” 博客,請務必保留此出處http://ghbsunny.blog.51cto.com/7759574/1962589

shell 編程 之 小技巧