實例對 各種情況的測試計算
[hcr@slave2 temp]$ vim variable.sh #!/bin/bash a=2334 let "a += 1" echo "a = $a" echo #替換成字母 b=${a/23/BB} echo "b = $b" declare -i b echo "b = $b" let "b += 1" echo "b =$b" echo #替換成數字 c=BB34 echo "c = $c" d=${c/BB/23} echo "d = $d" let "d += 1" echo "d = $d" echo # 為空值 e="" echo "e = $e" let e+=1 echo "e = $e" # 為null echo echo "f = $f" let "f += 1" echo "f = $f" echo
shell中有3種變量:用戶變量、位置變量{pracessing parameter)和環境變量。其中用戶變
量在編程過程中使用最多,位置變量在對參數判斷和命令返回值判斷時會使用,環境變量主要是在程序運行的時候需要設置。
聲明變量
VarName=varValue
聲明本地變量 local
但是必須得在腳本中去寫。
Shell中的特殊符號
特殊字符
含義
用法
~
主目錄,相當於 $HOME
cd ~
#
shell腳木中的注釋
# 注釋
··
命令替換.例如·pwd·返回pwd命令執行的結果字符串
abc=·which hadoop·
$
變量表達式符號
"a = $a"
&
後台作業,將此符號置於命令末端,則讓命令於後台運行
sh start.sh &
*
字符串通配符
ls a* >>f.txt
()
在括號中執行子shell命令
(let "e = $b + $c";echo $e)
\
轉義下一個字符
\\
|
管道
ps -ef |grep tomcat
[]
開始字符集通配符號和 if表達式
ls [a-z]*.sh
if [ "$1" != 0 ];then if
{}
命令塊
a=${aa/12/34}
;
shell命令分隔符
(let "e = $b + $c";echo $e)
‘’
強引用
a='abc';
“”
弱引用
a="$a"
<
輸入重定向
cat < a.txt > b.txt
>
輸出重定向
cat a.txt > b.txt
/
路徑名目錄分隔符
cd /
?
單個任意字符
ll ??.sh
!
邏輯NOT
ll [!a-b].txt
替換運算符
:-
${varname:-word}
在符號前的變量如果存在且非空則返回符號前的變量,否則返回符號後的字符
echo ${name:-'else'}
:=
${varname:=word}
在符號前的變量如果存在且非空則返回符號前的變量,否則講把符號後的字符賦值給符號前的變量
echo ${name:='else'}
:?
${varname:?word}
在符號前的變量如果存在且非空則返回符號前的變量,否則打印符號後的字符
echo ${name:?'else'}
:+
${varname:+word}
在符號前的變量如果存在則返回符號後的變量,否則返回null
echo ${name:+'else'}
如果上邊的替換運算符去掉冒號(:) ,就是一樣用但是條件少了一個且非空
匹配運算符
${varname#pattern}
必須以開頭匹配pattern模式的最短字符串將被刪除,返回剩余的字符串。否則返回全部
echo ${path#/*sr/}
${varname##pattern}
必須以開頭匹配pattern模式的最長字符串將被刪除,返回剩余的字符串。否則返回全部
echo ${path##/*sr/}
${varname%pattern}
必須以結尾匹配pattern模式的最短字符串將被刪除,返回剩余的字符串。否則返回全部
echo ${path%/*}
${varname%%pattern}
必須以結尾匹配pattern模式的最長字符串將被刪除,返回剩余的字符串。否則返回全部
echo ${path%%/*}
${varname/pattern/string}
匹配開始pattern模式的第一個字符串將被替換成string,如果string為null那麼匹配的東西將被刪除,返回處理後的數據。
echo ${path/hadoop/hadoop-0.2}
${varname//pattern/string}
匹配開始pattern模式的所有字符串將被替換成string,如果string為null那麼匹配的東西將被刪除,返回處理後的數據。
echo ${path//hadoop/hadoop-0.2}
${varname/#pattern/string}
必須以開頭匹配開始pattern模式的最短字符串將被替換成string,如果string為null那麼匹配的東西將被刪除,返回處理後的數據。
echo ${path/#\/usr/\/www}或者
echo ${path/#‘/usr’/‘/www’}
${varname/%pattern/string}
必須以結尾匹配開始pattern模式的最短字符串將被替換成string,如果string為null那麼匹配的東西將被刪除,返回處理後的數據。
echo ${path/%\/usr/\/www}
位置變量也稱系統變量、位置參數,是shell腳本運行時傳遞給腳本的參數,同時也表示在shell函數內部的函數參數。它們的名稱是以數字命名(由於歷史原因,直接引用的位置參數只能從$0到$9超過這個范圍則必須用括號括起來,如${10}。
shell內置了一個shift命令,shift命令可以“截去”參數列表最左端的一個。執行了shift後,$1的值將永遠一丟失,而$2的舊值會被賦給$1,以此類推。表達參數總數的$#將會減一。shift是個可帶參數的命令,例如,shift 2表示截去兩個參數,而單純的shift命令的含義是shift 1。
[root@ebsdi-23260-oozie tmpFile]# cat shift.sh #!/bin/bash while [ -e $1 ]; do cat $1 shift done
[root@ebsdi-23260-oozie tmpFile]# vim for.sh #!/bin/bash for file in $* do cat $file done ~
常用的環境變量
名稱
描述
PATH
命令搜索路補,以胃號為分隔符。注意與D0S不同的是,
當前目錄不在系統路徑裡
HOME
用戶home目錄的路徑名,是cd命令的默認參數
COLUMNS
定義了命令編輯模式下可使用命令行的長度
EDITOR
默認的行編輯器
VISUAL
默認的可視編輯器
FCEDIT
命令fc使用的編輯器
HISTFILE
命令歷史文件
HISTSIZE
命令歷史文件中最多可包含的命令條數
HISTFILESIZE
命令歷史文件中包含的最大行數
IFS
定義shell使用的分隔符
指向一個需要shell監視其修改時問的文件。
當該文件修改後,Shell將發消息"You have a mail"給用戶
MAILCHECK
shell檢查MAIL文件的周期,單位是秒。
SHELL
shell的路徑名
TERM
終端類型
TMOUT
shell自動退出的時間,單位為秒,若設為0,則禁正shell自動退出
PROMPT_COMMAND
指定在卞命令提示符前應執行的命令
PS1
主命令提示符
PS2
二級命令提示符,命令執行過程中要求輸入數據時用
PS3
select的命令提示符
PS4
調試命令提示符
MANPATH
尋找手冊頁的路徑,以胃號分隔
LOGNAME
用戶登錄名
MAILPATH
功能與MAIL類似。但可以用一組文件,
以冒號分隔,每個文件後跟一個問號和一條發向用戶的消息
LD_LIBARAY_PATH
尋找庫的路徑,以冒號分割
shell使用一些啟動文件來協助創建一個運行環境,其中每個文件都有特定的用途,對登錄
和交互環境的影響也各不相同。/etc目錄下的文件提供全局設置,如果用戶主目錄下存在同名文件,它將覆蓋全局設置。
使用/bin/login讀取/etc/passwd文件成功登陸後,啟動了一個交互登錄shell。用命令行可以啟動一個交互非登錄shell(例如[prompt] $/hin/bash )。非交互shel l通常出現在shell腳本運行的時候,之所以稱為非交互的,因為它正在運行一個腳本,而且命令與命令之間並不等待用戶的輸入。
無論運行什麼shell,文件/etc/enviranment都先運行。即使用rexedc和rshd開始的shell,也應該設置定義在/etc/enviranment文件中的環境變量。
/etc/enviranment設置諸如最小搜索路徑、時區、語言等用戶環境。這個文件不是一個
shellscript,並且只接受以下數據格式:
name=<value>
(環境變量名=變量值)
init開始的所有進程都要執行這個文件,它影響所有的登錄shell .
作為一種完整的編程語言,Linuxshell必定不能缺少函數( function)支持:一段獨立的程序
代碼用於執行一個完整的單項工作。函數復用是優質代碼的一大特征,故在一些大型的程序裡,常常可以見到函數的身影。
當shell執行函數時,並不獨立創建子進程。常用的做法是,將函數寫入其他文件中,當需要的時候才將它們載入腳本。
交互shell在獲得用戶輸入時,並不是直接就在PATH路徑中查找,而是按照固定順序依次移
找命令位置。搜索順序為;
別名 即使用aliascommand="..",創建的命令。
關鍵字 如if, fvro
函數 自定義的一些函數
內置命令 如cd, pwd等命令。
外部命令 即腳木或可執行程序,這才在path路徑中查找
由此可見,在同名時,函數的優先級高於腳本。可以使用內置命令 command,buildin 和enable改變優先級順序,它允許你將函數、別名和腳本文件定義成相同的名字,井選抒執行其中之一。
如果想要知道執行的命令是哪種類型,可以使用type命令。當重命名時,type命令會告訴你真正被執行的命令的來源是別名、函數或外部命令。
[houchangren@ebsdi-23260-oozie shell]$ type user_login
user_login is a function
user_login ()
{
if who | grep $1 >> /dev/null; then
echo " user $1 is on";
else
echo " user $1 is off";
fi
}
[houchangren@ebsdi-23260-oozie shell]$ type ll
ll is aliased to `ls -l --color=tty'
[houchangren@ebsdi-23260-oozie shell]$ type ls
ls is aliased to `ls --color=tty'
[houchangren@ebsdi-23260-oozie shell]$ type cat
cat is hashed (/bin/cat)
函數的使用規則
函數使用時,遵循一些重要規則:
》函數必須先定義,後使用。
》函數在當前環境下運行,共享調用它的腳木中的變量,並且,函數允許你以給位置參數賦值的方式向函數傳遞參數。函數體內部可以使用local限定詞創建局部變量。
》如果在函數中使用exit命令,會退出腳本。如果想退回到原本調用函數的地方,則使用 return命令。
》函數的return語句返回函數執行最後一條命令的退出狀態。
》使用內置命令export -f 可以將函數等出到子shell中。
》如果函數保存在其他文件巾,可以使用source或dot(就是圓點./start.sh)命令將它們裝入當前腳木。
》函數可以遞歸調用,並且沒有調用限制。
》可以使用declare -f 找到登錄會話中定義的函數。函數會按照字母順序打印所有的函數定義。這個定義列表可能會很長,需要使用文本閱讀器more或less查看。如果僅僅想看函數名,則使用declare -F語句。
如果想在每次啟動系統時自動加載函數,則只需要將函數寫入啟動文件中。例如
$HOME/.profile中即可,則每次啟動時,source$HOME/.profile都會自動加載函數.
函數定義
[houchangren@ebsdi-23260-oozie shell]$ cat user_login.sh #!/bin/bash function user_login(){ if who | grep $1 >> /dev/null ; then echo " user $1 is on" else echo " user $1 is off" fi } [houchangren@ebsdi-23260-oozie shell]$ source user_login.sh [houchangren@ebsdi-23260-oozie shell]$ user_login2 23 bash: user_login2: command not found [houchangren@ebsdi-23260-oozie shell]$ user_login erpmerge user erpmerge is on [houchangren@ebsdi-23260-oozie shell]$ user_login hbase user hbase is off [houchangren@ebsdi-23260-oozie shell]$ unset -f user_login
使用source 讀入文件內容
然後使用操作
unset -f 命令可以取消函數
由於函數是在當前shell中執行,所以變量對於函數和shell都可見。在函數內部對變量做的任何改動也會影響shell的環境。
參數 你可以像使用命令一樣,向函數傳遞位置參數,位置參數是函數私有的,對位置參數的任何操作並不會影響函數外部使用的枉何參數。
局部變量限定詞local 當使用local時,定義的變量為函數的內部變量。內部變量在函數退出時消失,不會影響到外部同名的變量。
返回方式return return命令可以在函數體內返回函數被調用的位置。如果沒有指定return的參數,則函數返回最後一條命令的退出狀態。return命令同樣也可以返回傳給它的參數。按照規定,return命令只能返回D到255之間的整數。如果在函數體內使用exit命令,則退出整個腳本。
[houchangren@ebsdi-23260-oozie shell]$ cat add.sh #!/bin/bash _add(){ let "sum=$1+$2" return $sum } [houchangren@ebsdi-23260-oozie shell]$ [houchangren@ebsdi-23260-oozie shell]$ _add 12 23 [houchangren@ebsdi-23260-oozie shell]$ echo $? 35
If/else
if who | grep 'sdfsdfds'; then echo 'right'; elseif who | grep 'sdfsdfsdfsd'; echo 'right'; else echo 'wrong'; fi
If [test] ; then do cmd elseif [test]; then docmd; else do cmd; fi
ifelse組合,
if else
if elseif
if elseif if
退出狀態
每條命令或函數,在退出時都會返回一個小的整數值給調用它的程序。這就是命令或函數的退出狀態(exit status )。與c語言稍有不同的是,在判斷語句中,條件(cnndition)實際上是語句列表,而不是般的布爾表達式。
按照慣例,函數以及命令的退出狀態用0來表示成功,而非零表示失敗。
POSIX中定義了退出狀態對應的值
值
描述
0
成功
>0
在重定向或者單詞展開期間(~、變量、命令、算數展開、單詞切割等)操作失敗
1-125
命令退出失敗。特定退出值的定義,參見不同命令的定義
126
命令找到而無法執行命令文件
127
命令無法找到
>128
命令因受到信號而死亡
Not and or
If [ !condition]; then statement if If [ condition && condition2]; then statement if If [ condition || condition2]; then statement if
If語句
if test 2 -gt 3; then echo '大於'; fi if [ 2 -gt 3 ]; then echo '大於'; fi
注意點,在使用 [ ]這個的時候一定要記得參數和符號之前有空格
字符串比較
-z string
字符串string 為空串(長度為0)時返回真
-n string
字符串string 為非空串時返回真
str1 = str2
字符串str1 和字符串str2 相等時返回真
str1 == str2
同 =
str1 != str2
字符串str1 和字符串str2 不相等時返回真
str1 < str2
按字典順序排序,字符串str1 在字符串str2 之前
[houchangren@ebsdi-23260-oozie shell]$ cat if.sh #!/bin/bash if [ $1 = "test" ] then echo "right" fi [houchangren@ebsdi-23260-oozie shell]$ sh if.sh test right [houchangren@ebsdi-23260-oozie shell]$ sh if.sh test3 [houchangren@ebsdi-23260-oozie shell]$
字符串的操作符兩邊都必須有空格哦。
[houchangren@ebsdi-23260-oozie shell]$ cat checkUserIsExist.sh #!/bin/sh line=|grep $1 /etc/passwd | if [ -n $line ] then echo "user $1 exist" fi [houchangren@ebsdi-23260-oozie shell]$ sh checkUserIsExist.sh houchangren user houchangren exist
整數數值比較
int1 -eq int2
如果int1 等於int2,則返回真
int1 -ne int2
如果int1 不等於int2,則返回真
int1 -lt int2
如果int1 小於int2,則返回真
int1 -le int2
如果int1 小於等於int2,則返回真
int1 -gt int2
如果int1 大於int2,則返回真
int1 -ge int2
如果int1 大於等於int2,則返回真
<
小於(在雙括號裡使用)
(("$a" < "$b"))
<=
小於等於 (在雙括號裡使用)
(("$a" <= "$b"))
>
大於 (在雙括號裡使用)
(("$a" > "$b"))
>=
大於等於(在雙括號裡使用)
(("$a" >= "$b"))
考 :http://blog.csdn.net/ruishenh/article/details/17998921
文件屬性檢查
-b filename
當filename 存在並且是塊文件時返回真(返回0)
-c filename
當filename 存在並且是字符文件時返回真
-d pathname
當pathname 存在並且是一個目錄時返回真
-e pathname
當由pathname 指定的文件或目錄存在時返回真
-f filename
當filename 存在並且是正規文件時返回真
-g pathname
當由pathname 指定的文件或目錄存在並且設置了SGID 位時返回真
-h filename
當filename 存在並且是符號鏈接文件時返回真 (或 -L filename)
-k pathname
當由pathname 指定的文件或目錄存在並且設置了"粘滯"位時返回真
-p filename
當filename 存在並且是命名管道時返回真
-r pathname
當由pathname 指定的文件或目錄存在並且可讀時返回真
-s filename
當filename 存在並且文件大小大於0 時返回真
-S filename
當filename 存在並且是socket 時返回真
-t fd
當fd 是與終端設備相關聯的文件描述符時返回真
-u pathname
當由pathname 指定的文件或目錄存在並且設置了SUID 位時返回真
-w pathname
當由pathname 指定的文件或目錄存在並且可寫時返回真
-x pathname
當由pathname 指定的文件或目錄存在並且可執行時返回真
-O pathname
當由pathname 存在並且被當前進程的有效用戶id 的用戶擁有時返回真(字母O 大寫)
-G pathname
當由pathname 存在並且屬於當前進程的有效用戶id 的用戶的用戶組時返回真
file1 -nt file2
file1 比file2 新時返回真
file1 -ot file2
file1 比file2 舊時返回真
f1 -ef f2
f1和f2硬鏈接到的是一個文件是為真
測試腳本
[houchangren@ebsdi-23260-oozie shell]$ ll 總計 24 -rw-rw-r-- 1 houchangren houchangren 51 01-08 10:46 add.sh -rw-rw-r-- 1 houchangren houchangren 85 01-08 13:38 checkUserIsExist.sh -rwxrwxr-x 1 houchangren houchangren 284 01-08 13:55 testalg.sh [houchangren@ebsdi-23260-oozie shell]$ cat testalg.sh #!/bin/bash file=$1 if [ -d $file ] then echo "$file is dir" elif [ -f $file ] then echo "$file is file " if [ -r $file ] && [ -w $file ] && [ -x $file ] then echo "You have read,write,execute permission on $file"; fi else echo "$file is neither a file and a directory" fi [houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh /etc /etc is dir [houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh ../ ../ is dir [houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh testalg.sh testalg.sh is file You have read,write,execute permission on testalg.sh [houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh /dev/null /dev/null is neither a file and a directory [houchangren@ebsdi-23260-oozie shell]$
Case語句
當存在很多個邏輯判斷的時候if用起來就顯著那麼臃腫了。Case可以很簡潔的指定
case也是一個流程控制結構。Parscal中的case語句和C語言中的switch語句被用來測試諸
如整數和字符的簡單值。shell中的case語句。可以依據可包含通配符的模式測試字符串。
[houchangren@ebsdi-23260-oozie shell]$ cat testcase.sh #!/bin/bash case $1 in -f) echo "參數1是-f";; -d) echo "參數1是-d";; -x) echo "參數1是-x";; -w) echo "參數1是-w";; *) echo "輸入的參數不是預先估的參數!";; esac [houchangren@ebsdi-23260-oozie shell]$ sh testcase.sh -w 參數1是-w [houchangren@ebsdi-23260-oozie shell]$ sh testcase.sh -ll 輸入的參數不是預先估的參數!
在眾多高級語言中,循環總是不可缺少的元素。循環一讓我們控制某些代碼的重復行為,或允許對多個對象操作。
for循環是最簡單的循環,我們在許多編程語言中都可以見到它的身影。在shell腳本裡,對象可以是命令行參數、文件名,或者任何、可以以列表格式建立的東西。
[houchangren@ebsdi-23260-oozie shell]$ for file in *.sh
> do
> echo $file
> done
add.sh
a.sh
checkUserIsExist.sh
if.sh
testalg.sh
testcase.sh
user_login.sh
[houchangren@ebsdi-23260-oozie shell]$
在for循環中,如果in list被省略,則默認為in"$@",即命令行參數的引用列表。就好像你已經輸入了for name in “$@”。
[houchangren@ebsdi-23260-oozie shell]$ cat testfor.sh
#!/bin/sh
for param
do
echo $param
done
[houchangren@ebsdi-23260-oozie shell]$ sh testfor.sh 1
1
[houchangren@ebsdi-23260-oozie shell]$ sh testfor.sh 1 2
1
2
[houchangren@ebsdi-23260-oozie shell]$ sh testfor.sh 1 2 3 4
1
2
3
4
[houchangren@ebsdi-23260-oozie shell]$
While 和傳統中的操作一樣
While [ condition ]
do
docmd
done
until [ condition ]
do
docmd
done
while和until的操作一樣,就是條件處理循環的時候是相反的。While是條件=true接著循環
break和continue語句允許對循環的運行精確控制:跳出循環或重新執行循環。
當嵌套層超過一層的時候可以指定break或者continue後加數字跳出(繼續)指定的層
[houchangren@ebsdi-23260-oozie shell]$ cat testwhile.sh
#!/bin/bash
num=0
while true
do
echo "while1- $num"
while true
do
echo "while2- $num"
while true
do
echo "while3- $num"
num=$(($num+1))
case $num in
5 ) break 2;;
10 ) break 3;;
* ) break 1 ;;
esac
done
done
if [ $num -ge $1 ];
then
break 1
fi
done
[houchangren@ebsdi-23260-oozie shell]$ sh testwhile.sh 10
while1- 0
while2- 0
while3- 0
while2- 1
while3- 1
while2- 2
while3- 2
while2- 3
while3- 3
while2- 4
while3- 4
while1- 5
while2- 5
while3- 5
while2- 6
while3- 6
while2- 7
while3- 7
while2- 8
while3- 8
while2- 9
while3- 9
[houchangren@ebsdi-23260-oozie shell]$
實例
[houchangren@ebsdi-23260-oozie shell]$ cat whileexample.sh #!/bin/bash author=false list=false file="" while [ $# -ge 0 ] do case $1 in -f) file=$2;echo "filename:$file"; shift ;; -l) list=true;; -a) author=true;; --) shift;break ;; -*) echo $0:$1:unrecognized option ;; * ) break ;; esac shift done [houchangren@ebsdi-23260-oozie shell]$ sh whileexample.sh -f whileexample.sh filename:whileexample.sh [houchangren@ebsdi-23260-oozie shell]$ sh whileexample.sh -fx wer whileexample.sh:-fx:unrecognized option [houchangren@ebsdi-23260-oozie shell]$用getopts工具來格式化參數
Getopts參考
http://www.2cto.com/os/201309/246174.html
[houchangren@ebsdi-23260-oozie shell]$ cat whileexample2.sh #!/bin/bash author=false list=false file="" while getopts alf: opt do case $opt in f) file=$OPTARG;echo "file:$file" ;; l) list=true ;; a) author=ture;; esac done shift $(($OPTIND -1)) [houchangren@ebsdi-23260-oozie shell]$ sh whileexample2.sh -f whileexample.sh file:whileexample.sh [houchangren@ebsdi-23260-oozie shell]$