一、函數:
1.概述:Shell函數類似于Shell腳本,里面存放了一系列的指令,不過Shell的函數存在于內存,而不是硬盤文件,所以速度很快,另外,Shell還能對函數進行預處理,所以函數的啟動比腳本更快。shell允許將一組命令集或語句形成一個可用塊,這些塊稱為shell函數。
2.語法:
function 函數名() {
語句
[return]
}
解析:所有函數在使用前必須定義。這意味著必須將函數放在腳本開始部分,直至shell解釋器首次發(fā)現它時,才可以使用。調用函數僅使用其函數名即可。函數中的關鍵字“return”可以放到函數體的任意位置,通常用于返回某些值,Shell在執(zhí)行到return之后,就停止往下執(zhí)行,返回到主程序的調用行,return的返回值只能是0~256之間的一個整數,返回值將保存到變量“$?”中。
3.shell函數的退出及刪除:
函數結束之后會返回調用函數的部分繼續(xù)執(zhí)行,
退出函數體:exit退出整個腳本、break語句來中斷函數的執(zhí)行。
shell中查詢函數及刪除:
source或. 腳本 ##將函數載入到內存
declare -f ##可以顯示定義的函數內容
declare -F ##可以只顯示定義的函數名
unset -f ##可以從Shell內存中刪除函數
4.變量:
全局變量:默認情況下,腳本中定義的任何變量都是全局變量,在函數外定義的變量可在函數內正常訪問。
局部變量:函數內部使用的任何變量都可以用“l(fā)ocal 變量名=值”聲明成局部變量,局部變量只能在函數體內生效。
5.案例:
案例一:函數的基本使用
[root@localhost ~]# vi func_linuxfan.sh
#!/bin/bash
read -p "輸入第一個數:" ANum
function linuxfan(){
echo "這個函數的功能是兩個數進行相加:"
read -p "輸入第二個數:" BNum
echo "您輸入的數是$ANum和$BNum! "
SUM=$(expr $ANum + $BNum)
echo "兩個數相加的結果是:$SUM"
local A="哈哈!"
echo "\$A是使用了local聲明的局部變量,在函數體內情況是:$A"
echo "\$ANum是在函數體外的變量,函數體內調用它的情況是:$ANum"
return 0 ##設置返回值
}
linuxfan ##調用函數
echo "\$A 在函數體外,結果是這樣的:$A"
echo "\$BNum 在函數體外,結果是這樣的:$BNum"
:wq
[root@localhost ~]# chmod +x func_linuxfan.sh
[root@localhost ~]# ./func_linuxfan.sh
輸入第一個數:123
這個函數的功能是兩個數進行相加:
輸入第二個數:456
您輸入的數是123和456!
兩個數相加的結果是:579
$A是使用了local聲明的局部變量,在函數體內情況是:哈哈
$ANum是在函數體外的變量,函數體內調用它的情況是:123
$A 在函數體外,結果是這樣的:
$B 在函數體外,結果是這樣的:
[root@localhost ~]# source func_linuxfan.sh ##從腳本文件中載入函數
[root@localhost bin]# declare -f ##顯示當前shell中函數內容
linuxfan ()
{
省略函數體內的內容。
}
[root@localhost bin]# declare -F ##查看當前shell中函數名稱
declare -f linuxfan
[root@localhost bin]# unset -f linuxfan ##刪除當前shell中的函數
[root@localhost bin]# declare -F ##查看驗證
案例二:函數參數的傳遞
函數可以通過位置變量傳遞參數。
函數名 參數1 參數2 參數3 參數4 ...
[root@localhost ~]# vi fun-paramters.sh
#!/bin/bash
funparam(){
echo "\$1可以給函數傳遞第一個參數,函數的第一個參數:$1"
echo "\$2可以給函數傳遞第二個參數,函數的第二個參數:$2"
echo "\$7可以給函數傳遞第七個參數,函數的第七個參數:$7"
echo "\${10}可以給函數傳遞第十個參數,函數的第十個參數:${10}"
echo "\${11}可以給函數傳遞第十一個參數,函數的第十一個參數:${11}"
echo "函數有$#個參數,函數參數具體內容是$*"
}
funparam 1 2 3 4 5 6 11 8 9 66 99
echo "腳本后的參數\$1是$1;"
echo "腳本后的參數\$2是$2;"
echo "腳本后的參數\$3是$3;"
echo "腳本后的參數\$4是$4;"
echo "腳本后的參數\$5是$5;"
:wq
[root@localhost ~]# chmod +x fun-paramters.sh
[root@localhost ~]# ./fun-paramters.sh a b c d f e
$1可以給函數傳遞第一個參數,函數的第一個參數:1
$2可以給函數傳遞第一個參數,函數的第一個參數:2
$7可以給函數傳遞第一個參數,函數的第一個參數:11
${10}可以給函數傳遞第一個參數,函數的第一個參數:66
${11}可以給函數傳遞第一個參數,函數的第一個參數:99
函數有11個參數,函數參數具體內容是1 2 3 4 5 6 11 8 9 66 99
腳本后的參數\$1是a;
腳本后的參數\$1是b;
腳本后的參數\$1是c;
腳本后的參數\$1是d;
腳本后的參數\$1是f;
[root@localhost ~]# cat test.sh ##將shell命令行中的參數傳遞給函數
#!/bin/bash
function test(){
echo "$1 $2 $3"
}
test $*
[root@localhost ~]# ./ test.sh a b c
a b c
案例三:
擴展學習(更多練習):
向系統(tǒng)學習函數的使用:
http://www.cnblogs.com/image-eye/archive/2011/10/26/2220405.html ##請大家閱讀/etc/init.d/funcations詳解,至少搞懂daemon和killproc兩個函數的作用。然后靜下心來閱讀這個腳本,并給它添加注釋你能學會很多東西:
[root@localhost ~]# cat /etc/init.d/vsftpd ##這是vsftpd的啟動腳本,非常經典
#!/bin/bash
#
### BEGIN INIT INFO
# Provides: vsftpd
# Required-Start: $local_fs $network $named $remote_fs $syslog
# Required-Stop: $local_fs $network $named $remote_fs $syslog
# Short-Description: Very Secure Ftp Daemon
# Description: vsftpd is a Very Secure FTP daemon. It was written completely from
# scratch
### END INIT INFO
# vsftpd This shell script takes care of starting and stopping
# standalone vsftpd.
#
# chkconfig: - 60 50
# description: Vsftpd is a ftp daemon, which is the program \
# that answers incoming ftp service requests.
# processname: vsftpd
# config: /etc/vsftpd/vsftpd.conf
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
RETVAL=0
prog="vsftpd"
start() {
# Start daemons.
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 1
[ -x /usr/sbin/vsftpd ] || exit 1
if [ -d /etc/vsftpd ] ; then
CONFS=`ls /etc/vsftpd/*.conf 2>/dev/null`
[ -z "$CONFS" ] && exit 6
PROC_FAILED=0
for i in $CONFS; do
site=`basename $i .conf`
echo -n $"Starting $prog for $site: "
daemon /usr/sbin/vsftpd $i
RETVAL=$?
echo
if [ $RETVAL -eq 0 ] && [ ! -f /var/lock/subsys/$prog ]; then
touch /var/lock/subsys/$prog
elif [ $RETVAL -ne 0 ]; then
ps -FC vsftpd | grep "$i" > /dev/null
RETVAL=$?
if [ $PROC_FAILED -eq 0 ] && [ $RETVAL -ne 0 ]; then
PROC_FAILED=1
fi
fi
done
if [ $RETVAL -eq 0 ] && [ $PROC_FAILED -ne 0 ]; then
RETVAL=1
fi
else
RETVAL=1
fi
return $RETVAL
}
stop() {
# Stop daemons.
echo -n $"Shutting down $prog: "
killproc $prog
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
return $RETVAL
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
stop
start
RETVAL=$?
;;
condrestart|try-restart|force-reload)
if [ -f /var/lock/subsys/$prog ]; then
stop
start
RETVAL=$?
fi
;;
status)
status $prog
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|restart|try-restart|force-reload|status}"
exit 1
esac
exit $RETVAL
案例四:測試主機訪問url路徑
二、shell數組:
1.概述:數組就是一組數據類型相同集合;
2.數組的定義及使用:
[root@localhost bin]# arr1=() ##定義空元素數組
[root@localhost bin]# arr2=(1 2 3 4 5 6) ##定義數字元素的數組
[root@localhost bin]# arr3=("有夢想" "向往遠方和詩" "高薪就業(yè)" "靜心沉迷于學習!") ##定義字符串元素的數組,注意用引號(單、雙引號皆可)
[root@localhost bin]# echo ${arr2[0]}
1
[root@localhost bin]# echo ${arr2[3]}
4
[root@localhost bin]# echo ${arr3[3]}
靜心沉迷于學習!
[root@localhost bin]# echo ${arr3[*]}
有夢想 向往遠方和詩 高薪就業(yè) 靜心沉迷于學習!
[root@localhost bin]# for i in ${arr3[*]};do echo $i;done
有夢想
向往遠方和詩
高薪就業(yè)
靜心沉迷于學習!
[root@localhost bin]# echo ${#arr3[*]} ##獲取數組的長度
4
[root@localhost bin]# echo ${#arr3[@]}
4
數組賦值格式:數組名[下標]=值,如果下標不存在,則新增數組元素; 下標已有,則覆蓋值。
[root@localhost bin]# echo ${arr2[*]} ##獲取數組所有元素
1 2 3 4 5 6
[root@localhost bin]# arr2[6]=8 ##下標為6(第七個)的內容為8,添加元素
[root@localhost bin]# echo ${arr2[*]} ##驗證
1 2 3 4 5 6 8
[root@localhost bin]# arr2[2]=8 ##修改下標為2的元素為8,覆蓋原有值
[root@localhost bin]# echo ${arr2[*]} ##驗證
1 2 8 4 5 6 8
數組分片的格式:${數組名[*或@]:起始位:長度},截取部分數組,返回字符串,中間用空格分隔;將結果使用“()”,則得到新的切片數組。
[root@localhost bin]# echo ${#arr3[*]}
4
[root@localhost bin]# echo ${arr3[*]:0:1}
有夢想
[root@localhost bin]# echo ${arr3[*]:2:2}
高薪就業(yè) 靜心沉迷于學習!
[root@localhost bin]# arr4=(${arr3[*]:2:2})
[root@localhost bin]# echo ${arr4[*]}
高薪就業(yè) 靜心沉迷于學習!
數組替換元素的格式:${數組名[*或@]/查找字符/替換字符}, 不會修改原數組;如需修改的數組,將結果使用“()”賦給新數組。
[root@localhost bin]# echo ${arr2[*]}
1 2 8 4 5 6 8
[root@localhost bin]# echo ${arr2[*]/4/9}
1 2 8 9 5 6 8
[root@localhost bin]# arr5=${arr2[*]/4/9}
[root@localhost bin]# echo ${arr5[*]}
1 2 8 9 5 6 8
刪除數組的格式:unset 數組,清除整個數組; unset 數組[下標],清除單個元素。
[root@localhost bin]# echo ${arr3[*]}
有夢想 向往遠方和詩 高薪就業(yè) 靜心沉迷于學習!
[root@localhost bin]# unset arr3[0]
[root@localhost bin]# echo ${arr3[*]}
向往遠方和詩 高薪就業(yè) 靜心沉迷于學習!
[root@localhost bin]# unset arr3
[root@localhost bin]# echo ${arr3[*]}
三、shell當中括號的使用:
1.單小括號():
命令組:組合多條命令一起執(zhí)行,并按照順序執(zhí)行。
[root@www ~]# (umask 0077;mkdir -p test;ls -ld test)
替換命令:效果等于反撇,在命令中執(zhí)行命令,并將執(zhí)行結果交給命令處理。
[root@www ~]# rpm -qf $(which convert) ##查詢命令的安裝包
ImageMagick-6.5.4.7-6.el6_2.x86_64
用于初始化數組:如array=(a b c d)
[root@www ~]# array=(a b c d)
2.雙小括號(())
計算其他進制(二、八、十六)的數到十進制:
[root@www ~]# echo $((2#11)) ##二轉十
3
[root@www ~]# echo $((8#11)) ##八轉十
9
[root@www ~]# echo $((16#11)) ##十六轉十
17
[root@www ~]# echo $((16#1f))
31
[root@localhost bin]# echo $((3+2)) ##加減乘除取摸運算
5
[root@localhost bin]# echo $((3-2))
1
[root@localhost bin]# echo $((3*2))
6
[root@localhost bin]# echo $((3/2))
1
[root@localhost bin]# echo $((3%2))
1
重新定義變量:
[root@www ~]# a=5;((a++));echo $a
6
算術運算比較,雙括號內的變量可以不使用$,表達式用分號分開:
[root@www ~]# for i in {0..4};do echo $i;done
[root@www ~]# for i in $(seq 0 4);do echo $i;done
[root@www ~]# for ((i=0;i<5;i++));do echo $i;done ##上述三種都是一樣的效果
[root@www ~]# i=10
[root@www ~]# if ((i>5));then echo $i;fi
[root@www ~]# if [ $i -gt 5 ];then echo $i;fi ##兩個if的效果相同
3.中括號[ ]
條件表達式
[root@www ~]# [ -f /etc/hosts ]&&echo ok
[root@www ~]# test -f /etc/hosts &&echo ok
字符范圍。用作正則表達式的一部分,描述一個匹配的字符范圍。
[root@www ~]# i=1 ##case中使用的[0-9]|[a-z]|[A-Z]表示正則
[root@www ~]# case $i in [0-9]) echo "number"; ;; [a-z]|[A-Z]) echo "alph"; ;; esac
4.雙中括號[[ ]]
①[[是 bash 程序語言的關鍵字。并不是一個命令,[[ ]] 結構比[ ]結構更加通用。在[[和]]之間所有的字符都不會發(fā)生文件名擴展或者單詞分割,但是會發(fā)生參數擴展和命令替換。
②支持字符串的模式匹配,使用=~操作符時甚至支持shell的正則表達式。字符串比較時可以把右邊的作為一個模式,而不僅僅是一個字符串,比如[[ hello == hell? ]],結果為真。[[ ]] 中匹配字符串或通配符,不需要引號。
③使用[[ ... ]]條件判斷結構,而不是[ ... ],能夠防止腳本中的許多邏輯錯誤。比如,&&、||、<和> 操作符能夠正常存在于[[ ]]條件判斷結構中,但是如果出現在[ ]結構中的話,會報錯。比如可以直接使用if [[ $a != 1 && $a != 2 ]], 如果不使用雙括號, 則為if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ]。
[root@www ~]# a=3
[root@www ~]# if [ $a != 1 && $a != 2 ];then echo $a;fi ##報錯
-bash: [: missing `]'
[root@www ~]# if [[ $a != 1 && $a != 2 ]];then echo $a;fi ##成功執(zhí)行
3
[root@www ~]# if [ $a != 1 ] && [ $a != 2 ];then echo $a;fi ##執(zhí)行成功
3
5.花括號{ }
常規(guī)用法:
[root@www ~]# touch {a..z}.mp{3..5} ##..表示分割順序文件列表
[root@www ~]# ls {{a..e},h,y,z}.mp4
a.mp4 b.mp4 c.mp4 d.mp4 e.mp4 h.mp4 y.mp4 z.mp4
定義函數:代碼塊,又被稱為內部組,這個結構事實上創(chuàng)建了一個匿名函數 。與小括號中的命令不同,花括號內的命令不會新開一個子shell運行,即腳本余下部分仍可使用括號內變量。
字符串提取和替換:
${var:num},${var:num1:num2},${var/pattern/pattern},${var//pattern/pattern}
第一種模式:${var:num},這種模式時,shell在var中提取第num個字符到末尾的所有字符。若num為正數,從左邊0處開始;若num為負數,從右邊開始提取字串,但必須使用在冒號后面加空格或一個數字或整個num加上括號,如${var: -2}、${var:1-3}或${+var:(-2)}。
[root@www ~]# var=www.linuxfan.cn
[root@www ~]# echo ${var:4}
linuxfan.cn
[root@www ~]# echo ${var:(-2)}
cn
第二種模式:${var:num1:num2},num1是位置,num2是長度。表示從$var字符串的第$num1個位置開始提取長度為$num2的子串。不能為負數。
[root@www ~]# var=www.linuxfan.cn
[root@www ~]# echo ${var:4:5}
linux
[root@www ~]# echo ${var:1:3}
ww.
[root@www ~]# echo ${var:0:3}
www
第三種模式:${var/pattern/pattern}表示將var字符串的第一個匹配的pattern替換為另一個pattern。。
[root@www ~]# var=www.linuxfan.cn
[root@www ~]# echo ${var/www/dns}
dns.linuxfan.cn
第四種模式:${var//pattern/pattern}表示將var字符串中的所有能匹配的pattern替換為另一個pattern。
[root@www ~]# var=www.linuxfan.cn
[root@www ~]# echo ${var/n/N}
www.liNuxfan.cn
[root@www ~]# echo ${var//n/N}
www.liNuxfaN.cN
6.多條命令執(zhí)行
單小括號:(cmd1;cmd2;cmd3)新開一個子shell順序執(zhí)行命令cmd1,cmd2,cmd3, 各命令之間用分號隔開, 最后一個命令后可以沒有分號。
[root@www tmp]# (touch index.html;rm -rf index.html;ls -l;)
單大括號:{ cmd1;cmd2;cmd3;} 在當前shell順序執(zhí)行命令cmd1,cmd2,cmd3, 各命令之間用分號隔開, 最后一個命令后必須有分號, 括號兩側必須有空格。
[root@www tmp]# {touch index.html;rm -rf index.html;ls -l;} ##開始的{后無空格報錯
-bash: syntax error near unexpected token `}'
[root@www tmp]# { touch index.html;rm -rf index.html;ls -l }
[root@www tmp]# { touch index.html;rm -rf index.html;ls -l; } ##最后一條命令必須;
總用量 0
注:對{}和()而言, 括號中的重定向符只影響該條命令,而括號外的重定向符影響到括號中的所有命令。