shell 指令碼-符號-基礎語法
為了便於識別 建議 以.sh 結尾
shell指令碼 可以放上所有的命令列的指令(源於bash)
shell指令碼 是 解釋型語言 c/c++ 是編譯型語言
下面用到的 shell程式碼sh_1.sh
#!/bin/bash cd../ ls pwd
解釋型指令碼的執行過程:
script.sh 是文字檔案,根本沒有程式碼段和 _start 函式 , exec 怎麼執行。
解釋:
Shell會fork 一個子程序並呼叫 exec執行 ./script.sh這個程式,exec 系統呼叫應該把子程序的程式碼
段替換成./script.sh程式的程式碼段 ,並從它的 _start開始執行。然而 script.sh是個文字檔案
沒有程式碼段和 _start函式 ,怎麼辦呢 ?其實 exec還有另外一種機制 ,如果要執行的是一個文字文
件, 並且第一行用 Shebang 指定了直譯器 ,則用 直譯器程式的程式碼段替換當前程序 ,並且從解釋
器 的_start開始執行 ,而這個文字檔案被當作命令列引數傳給直譯器 。因此, 執行上述指令碼相
當於執 行程式
1. 互動 Shell(bash)fork/exec一個子 Shell(sh)用於執行指令碼 ,父程序 bash等待子程序 sh終止。
2. sh讀取指令碼中的 cd ..命令 ,呼叫相應的函式 執行內建命令 ,改變當前工作目錄為上一級
目 錄。
3. sh讀取指令碼中的 ls
4. ls終止後 ,sh繼續執行 ,讀到指令碼檔案末尾 ,sh終止。
5. sh終止後 ,bash繼續執行 ,列印提示符等待使用者輸入。
如果將命令列下輸入的命令用 ()括號括起來 ,那麼也會 fork出一個子 Shell執行小括號中的命令 ,
一 行中可以輸入由分號 ;隔開的多個命令 ,比如 : $ (cd ..;ls -l)
和上面兩種方法執行 Shell指令碼的效果是相同的 ,cd ..命令改變的是子 Shell的 PWD,而不會影響
到 互動式Shell。
chmod + x script.sh方式
sh檔案中,cd ..
然而source ./script.sh 和 . ./script.sh 方式
則有不同的效果,cd ..命令是直接在互動式Shell1下執行的,改變互動式Shell的PWD
對於php 。。。指令碼語言 執行也是 直譯器這個流程
sh_1.sh程式碼:
#!/bin/bash
cd ../
ls
pwd
[[email protected] 1_shell]$ /bin/bash sh_1.sh // shell指令碼中 cd 直接在子bash中執行 整個過程父程序 不參與
1_shell
/home/bozi/linux_test/shell
[[email protected] 1_shell]$ pwd
/home/bozi/linux_test/shell/1_shell // 所以 不影響父程序 的路徑 還在子程序的路徑中
[[email protected] 1_shell]$ cd .. // cd內建命令 shell 自己直接親自執行(不建立子程序) 影響自己的路徑
[[email protected] shell]$ pwd
/home/bozi/linux_test/shell // 直接執行 影響了 跑到上級目錄
路徑
[[email protected] shell]$ ll
總用量 4
drwxrwxr-x. 2 bozi bozi 4096 8月 14 10:18 1_shell
[[email protected] shell]$ cd 1_shell/
[[email protected] 1_shell]$ ll
總用量 4
-rw-rw-r--. 1 bozi bozi 298 8月 14 10:18 sh_1.sh
source 與(. 命令一樣)
例子:
source 不建立子bash,遇見bash中有內建命令 cd 互動式shell(父程序自己直接執行) 所以 退出時 父程序的路徑 變了 影響父程序
[[email protected] 1_shell]$ ll
總用量 4
-rw-rw-r--. 1 bozi bozi 298 8月 14 10:18 sh_1.sh
[[email protected] 1_shell]$ source sh_1.sh
1_shell
/home/bozi/linux_test/shell
[[email protected] shell]$ pwd
/home/bozi/linux_test/shell
.命令 效果相同
[[email protected] 1_shell]$ . sh_1.sh
1_shell
/home/bozi/linux_test/shell
[[email protected] shell]$ pwd
/home/bozi/linux_test/shell
set 顯示 本地變數 和 環境變數(本地變數只存在當前程序中)
env 只顯示環境變數 (環境變數 可以傳遞給 子程序 父子程序共享)
變數
shell 中 所有變數varname都是字串 ,且都是全域性本地變數 沒有int ,float等型別 顯示變數 用 $varname或 ${varname}
如果變數不存在 shell顯示空串
變數拼接 用{}花括號 如: ${varname}aaa $varname"aaa"
演示程式碼:
[[email protected]2_shell]$SHELL=1 [[email protected]2_shell]$echo$SHELL 1 [[email protected]2_shell]$echo$SHELLabc [[email protected]2_shell]$echo${SHELL} 1 [[email protected]2_shell]$echo${SHELL}abc 1abc
unset 取消一個變數
[[email protected]2_shell]#v=a [[email protected]2_shell]#echo$v a [[email protected]2_shell]#unset$v [[email protected]2_shell]#
顯示本shell的pid
[[email protected]2_shell]#echo$$ 6699
read
-p 提示符 -t 等待的秒數
[[email protected]2_shell]$read-p'>>'-t10arg >>nihao [[email protected]2_shell]$echo$arg nihao
陣列變數
var[1]="smallmin" var[2]="bigmin" var[3]="nicemin" echo"${var[1]},${var[2]},${var[3]}" [[email protected]2_shell]$./1_test.sh smallmin,bigmin,nicemin
test指令
兩個整數之間的判定
-eq 相等(equal)
-ne 不等(not equal)
-gt 大於 (greaater than)
-lt 小於 (less than)
-ge 大於等於 (greater than or equal)
-le 小於等於 (less than or equal)
例子:
[[email protected]2_shell]$test1-lt2;echo$? 0---------------》【真】 [[email protected]2_shell]$test5-lt2;echo$? 1
判定字串的資料
test-zstring[string為空返回true] test-nstring[string為空返回false] teststr1=str2[str1=str2回傳true] teststr1!=str2[str1與str2相等返回false] 例子: [[email protected]2_shell]$test-z"";echo$? 0 [[email protected]2_shell]$test-z"-";echo$? 1 [[email protected]2_shell]$test-n"";echo$? 1 [[email protected]2_shell]$test-n"-";echo$? 0 [[email protected]2_shell]$test"nihao"="hello";echo$? 1 [[email protected]2_shell]$test"nihao"=="hello";echo$? 1 [[email protected]2_shell]$test"nihao"!="hello";echo$? 0
error
[[email protected] 2_shell]$ test "nihao"=="hello" ; echo $?
0 ----》“==兩邊少空格 結果 不正確”
test擴充套件:
當要檢測系統上面某些檔案或者是相關的屬性時,利用test這個命令來工作真是好用得不得了,如檢查/dmtsai是否存在時,使用:test –e /dmtsai
上面的執行結果並不會顯示任何資訊,但最後可以通過$?或&&及||來顯示整個結果。
test –e /dmtsai && echo “exist” ||echo “Not exist”
最終結果可以顯示exist還是not exist。-e是測試一個東西存在不存在。常用的測試命令如下:
測試的標誌 | 代表意義 |
關於某個檔名的“檔案型別”判斷,如test – e filename表示存在否 | |
-e | 該檔名是否存在 |
-f | 該檔名是否存在且為檔案(file) |
-d | 該檔名是否存在且為目錄(directory) |
-b | 該檔名是否存在且為一個block device裝置 |
-c | 該檔名是否存在且為一個character device裝置 |
-S | 該檔名是否存在且為一個Socket檔案 |
-p | 該檔名是否存在且為一個FIFO(pipe)檔案 |
-L | 該檔名是否存在且為一個連線檔案 |
關於檔案的許可權檢測,如test –r filename表示可讀否(但root許可權常有例外) | |
-r | 檢測該檔名是否存在且具有“可讀”的許可權 |
-w | 檢測該檔名是否存在且具有“可寫”的許可權 |
-x | 檢測該檔名是否存在且具有“可執行”的許可權 |
-u | 檢測該檔名是否存在且具有“SUID”的屬性 |
-g | 檢測該檔名是否存在且具有“SGID“的屬性 |
-k | 檢測該檔名是否存在且具有“Sticky bit”的屬性 |
-s | 檢測該檔名是否存在且具有“非空白檔案” |
兩個檔案之間的比較,如test file1 –nt file2 | |
-nt | (newer than)判斷file1是否比file2新 |
-ot | (older than)判斷file1是否比file2舊 |
-ef | 判斷file1與file2是否為同一檔案,可用在判斷hard link的判定上。主要意義在於判定兩個檔案是否均指向同一個inode |
關於兩個整數之間的判定嗎,如test n1 –eq n2 | |
-eq | 兩數值相等(equal) |
-ne | 兩數值不等(not equal) |
-gt | N1大於n2(greate than) |
-lt | N1小於n2(less than) |
-ge | N1大於等於n2(greater than or equal) |
-le | N1小於等於n2(less than or equal) |
判定字串的資料 | |
test –z string | 判定字串是否為0,若string為空字串,則為true |
test –n string | 判定字串是否非為0,若string為空字串,則為false |
test str1 = str2 | 判定str1是否等於str2,若相等,則回傳true |
test str1 != str2 | 判定str1是否不等於str2,若相等,則回傳false |
多重條件判定,若test –r filename –a –x filename | |
-a | 兩個條件同時成立!如test –r file –a –x file,則file同時具有r與x許可權時,才回傳true |
-o | 任何一個條件成立!如test –r file –o –x file,則file具有r或x許可權時,就可回傳true |
! | 反向狀態,如test ! –x file,但file不具有x時,回傳true |
多重條件判定
-a [先當於 與&&]
-o 【或】
! 【非】
例子:
[[email protected]2_shell]$test1-eq1-a2-lt5;echo$? 0 [[email protected]2_shell]$test1-eq1-a5-lt2;echo$? 1
判斷符號[]
[[email protected]2_shell]$[""=="HOME"];echo$? 1 [[email protected]2_shell]$[""!="HOME"];echo$? 0
error
[[email protected]2_shell]$[""!="HOME"];echo$? 0 [[email protected]2_shell]$[""=="HOME"];echo$? 0
注意 空格不能少 否則出錯:
[[email protected] 2_shell]$ [ 空格"" 空格== 空格"HOME" 空格];echo $?
建議:
1 在中括號[]中的每個元件用 空格 隔開
2 在中括號內的變數, 最好用雙引號括起來
3 在中括號裡面的常量最好用單引號或 雙引號括起來
2的一個錯誤例子:
[[email protected]2_shell]$name="helloworld" [[email protected]2_shell]$[$name=="hello"] bash:[:toomanyarguments--------------------------》太多引數本來是兩個引數比較因為name變數的字串中間有空格不加“” 解析為[helloworld=="hello"]肯定引數太多 [[email protected]2_shell]$["$name"=="hello"] [[email protected]2_shell]$echo$? 1 [[email protected]2_shell]$["$name"!="hello"] [[email protected]2_shell]$echo$? 0
小練習:
read-p"pleaseinoput(Y/N):"yn ["$yn"=="Y"-o"$yn"=="y"]&&echo"ok,continue"&&exit0 ["$yn"=="N"-o"$yn"=="n"]&&echo"oh,interrupt"&&exit0 echo"Idontknowwhatyourchoniceis"&&exit0 執行: [[email protected]2_shell]$./1_test.sh pleaseinoput(Y/N):y ok,continue [[email protected]2_shell]$./1_test.sh pleaseinoput(Y/N):n oh,interrupt [[email protected]2_shell]$./1_test.sh pleaseinoput(Y/N): Idontknowwhatyourchoniceis
shell中&&和||的使用方法
&&運算子:
command1 && command2
&&左邊的命令(命令1)返回真(即返回0,成功被執行)後,&&右邊的命令(命令2)才能夠被執行;換句話說,“如果這個命令執行成功&&那麼執行這個命令”。
語法格式如下:
command1 && command2 [&& command3 ...]
1 命令之間使用 && 連線,實現邏輯與的功能。
2 只有在 && 左邊的命令返回真(命令返回值 $? == 0),&& 右邊的命令才會被執行。
3 只要有一個命令返回假(命令返回值 $? == 1),後面的命令就不會被執行。
||運算子:
command1 || command2
||則與&&相反。如果||左邊的命令(命令1)未執行成功,那麼就執行||右邊的命令(命令2);或者換句話說,“如果這個命令執行失敗了||那麼就執行這個命令。
1 命令之間使用 || 連線,實現邏輯或的功能。
2 只有在 || 左邊的命令返回假(命令返回值 $? == 1),|| 右邊的命令才會被執行。這和 c 語言中的邏輯或語法功能相同,即實現短路邏輯或操作。
3 只要有一個命令返回真(命令返回值 $? == 0),後面的命令就不會被執行。
&& || 與 -a -o
區別
-a -o 連線的是兩個表示式 即 測試條件
而 && 與 || 連線的是兩條 命令
程式碼:
val=10 str="hello" test$val-eq10-a"$str"=="hello" echo$? test$val-eq10&&test"$str"=="hello" echo$? 執行: [[email protected]2_shell]$./12_test.sh 0 0
預設變數 $0 $1 $2 ...
例子:$ ./1_test.sh nihao sunshine
$0 $1 $2
$# :代表後接的引數的個數, 如上例子為2
[email protected]:代表"$1" "$2" ... 之意, 每個變數獨立的用雙括號括起來
$*: 代表“$1c$2c$3c$4” c為分隔符號,預設是空格鍵
[email protected] 和 $*還是有所不同的 一般用 [email protected]
程式碼:
#!/bin/bash echo"\$0is$0" echo"\$1is$1" echo"\$2is$2" echo"\$#is$#" echo"\[email protected]is[email protected]" echo"\$*is$*"
執行:
[[email protected]2_shell]$./1_test.sh $0is./1_test.sh $1is $2is $#is0 [email protected]is $*is
[[email protected]2_shell]$./1_test.sh1234 $0is./1_test.sh $1is1 $2is2 $#is4 [email protected]is1234 $*is1234
程式碼:
echo"yourwholeparameteris===>$0" echo"totalparameternumbersis===>$#" ["$#"-lt2]&&echo"thenumbersofparamaterislessthan2.stophere"\ &&exit0; echo"yourwholeparameteris===>[email protected]" echo"the1stparameter===>$1" echo"the2ndparameter===>$2"
執行:
[[email protected]2_shell]$./1_test.sh yourwholeparameteris===>./1_test.sh totalparameternumbersis===>0 thenumbersofparamaterislessthan2.stophere [[email protected]2_shell]$./1_test.shnihaosunshine yourwholeparameteris===>./1_test.sh totalparameternumbersis===>2 yourwholeparameteris===>nihaosunshine the1stparameter===>nihao the2ndparameter===>sunshine
執行:
[[email protected]1_shell]$catsh_1.sh #!/bin/bash myint=10 echo'\$\\$myint\"' echo'###############' echo"\$\\$myint\"" [[email protected]2_shell]$./1_test.sh yourwholeparameteris===>./1_test.sh totalparameternumbersis===>0 thenumbersofparamaterislessthan2.stophere [[email protected]2_shell]$./1_test.shnihaosunshine yourwholeparameteris===>./1_test.sh totalparameternumbersis===>2 yourwholeparameteris===>nihaosunshine the1stparameter===>nihao the2ndparameter===>sunshine [[email protected]2_shell]$./1_test.shnihaosunshinehere yourwholeparameteris===>./1_test.sh totalparameternumbersis===>3 yourwholeparameteris===>nihaosunshinehere the1stparameter===>nihao the2ndparameter===>sunshine
shift:造成引數號碼偏移,移除前num個引數
shift+num num 及num之前的引數全部移除 num之後的引數從$1開始
如:
echo[email protected] echo"argcount$#" shift1 echo"aftershift1" echo[email protected] echo"argcount$#" shift3 echo"aftershift3" echo[email protected] echo"argcount$#"
執行:
[[email protected]2_shell]$./1_test.shonetwothreefourfivesixseven onetwothreefourfivesixseven argcount7 aftershift1 twothreefourfivesixseven argcount6 aftershift3 fivesixseven argcount3
條件判斷式
1 if ... then
if [條件判斷式];then
條件成立執行
fi
&&代表AND
|| 代表 or
程式碼:
#!/bin/bash read-p"pleaseinput(Y/N):"yn if["X$yn"=="XY"]||["X$yn"=="Xy"];then echo"ok,continue" exit0 fi if["X$yn"=="XN"]||["X$yn"=="Xn"];then echo"oh,interupt!" exit0 fi
執行:
pleaseinput(Y/N):y ok,continue [[email protected]2_shell]$./2_test.sh pleaseinput(Y/N):Y ok,continue [[email protected]2_shell]$./2_test.sh pleaseinput(Y/N):N oh,interupt! [[email protected]2_shell]$./2_test.sh pleaseinput(Y/N):n oh,interupt!
多重複雜條件判斷式
if [條件判斷式];then
條件成立
else
...
if
if [條件判斷式1];then
...
elif [條件判斷式2];then
...
else
...
if
程式碼:
read-p"pleaseinput(Y/N):"yn if["x$yn"=="xY"]||["x$yn"=="xy"];then echo"ok,continue" elif["x$yn"=="xN"]||["x$yn"=="xn"];then echo"oh,interupt" else echo"Idontknowwhatyourchoiceis" fi
執行:
[[email protected]2_shell]$vim2_test.sh [[email protected]2_shell]$./2_test.sh pleaseinput(Y/N):y ok,continue [[email protected]2_shell]$./2_test.sh pleaseinput(Y/N):n oh,interupt [[email protected]2_shell]$./2_test.sh pleaseinput(Y/N):s Idontknowwhatyourchoiceis 程式碼: testing=$(netstat-tuln|grep':80') if["X$testing"!="X"];then echo"WWWisrunninginyoursystem." fi testing=$(netstat-tuln|grep':22') if["X$testing"!="X"];then echo"SSHisrunninginyoursystem." fi testing=$(netstat-tuln|grep':21') if["X$testing"!="X"];then echo"FTPisrunninginyoursystem." fi testing=$(netstat-tuln|grep':25') if["X$tesing"!="X"];then echo"Mailisrunninginyoursystem." fi
執行:
[[email protected]2_shell]$./3_text.sh Now,Iwilldetectyourlinuxserver'sservices! Thewwww,ftp,ssh,andmailwillbedetect! SSHisrunninginyoursystem.
利用case ...... esac判斷
case $變數名稱 in
”第1個變數名稱“)
程式段
;;
”第2個變數名稱“)
程式段
;; # ;; 相當於break
*) #*)相當於default
程式段
;;
esac
程式碼:
#!/bin/bash case$1in "one") echo"yourchoiceisONE" ;; "two") echo"yourchoiceisTWO" ;; "three") echo"yourchoiceisTHREE" ;; *) echo"Usage$0{one|two|three}" ;; esac
執行:
[[email protected]2_shell]$./4_test.sh Usage./4_test.sh{one|two|three} [[email protected]2_shell]$./4_test.shone yourchoiceisONE [[email protected]2_shell]$./4_test.shtwo yourchoiceisTWO [[email protected]2_shell]$./4_test.shthree yourchoiceisTHREE
函式 function
函式的引數 也是$1$2$.... 但是函式體裡面的$1$2...與函式外面的 是相對獨立的
函式返回值:return後 用 $? 來接收 【返回值】(缺陷 返回257 是 1 範圍0-255)
程式碼:
#!/bin/bash functionprintit()#也可以不加關鍵字function即printit(){...}也是可以的 { echo-n"Yourchoiceis"#加上-n表示不斷行繼續在一行顯示 } case$1in "one") printit;echo$1|tr'a-z''A-Z'#大小寫轉化 ;; "two") printit;echo$1|tr'a-z''A-Z'#大小寫轉化 ;; "three") printit;echo$1|tr'a-z''A-Z'#大小寫轉化 ;; *) echo"Usage$0{one|two|three}" ;; esac
執行:
[[email protected]2_shell]$./5_test.shone YourchoiceisONE [[email protected]2_shell]$./5_test.sh Usage./5_test.sh{one|two|three} [[email protected]2_shell]$./5_test.shone YourchoiceisONE [[email protected]2_shell]$./5_test.shtwo YourchoiceisTWO [[email protected]2_shell]$./5_test.shthree YourchoiceisTHREE
經典的fork××× 【!!!立馬宕機】
.(){.|.&};.#遞迴呼叫後臺執行
類似的 function a() { a|a }; a
防範措施 ulimit -Hu num 限定使用者最多num個程序
-------------------------------------------------
以下程式段就是由Jaromil所作的在類UNIX系統的shell環境下觸發fork×××的shell指令碼程式碼,總共只用了13個字元(包括空格):
:(){ :|:& };:
註解如下:
:()# 定義函式,函式名為":",即每當輸入":"時就會自動呼叫{}內程式碼
{# ":"函式開始標識
:# 用遞迴方式呼叫":"函式本身
|# 並用管道(pipe)將其輸出引至...
:# 另一次遞迴呼叫的":"函式
# 綜上,":|:"表示的即是每次呼叫函式":"的時候就會生成兩份拷貝【二倍指數增長】
&# 呼叫間脫鉤,以使最初的":"函式被殺死後為其所呼叫的兩個":"函式還能繼續執行
}# ":"函式結束標識
;# ":"函式定義結束後將要進行的操作...
:# 呼叫":"函式,"引爆"fork×××
其中函式名“:”只是簡化的一例,實際實現時可以隨意設定,一個較易理解(將函式名替換為“forkbomb”)的版本如下:
forkbomb(){ forkbomb|forkbomb &} ; forkbomb
Windows下則可以批處理命令如下實現:
%0|%0
POSIX標準下的C與C++的實現:
#include <unistd.h>int main(){while(1) fork();return0;}
Perl語言的實現:
fork while fork
-------------------------------------------------
迴圈
while do done, until do done(不定迴圈)
程式碼:
#!/bin/bash while["X$yn"!="Xyes"-a"X$yn"!="XYES"] do read-p"pleaseinputyes/YEStostopthisprogram:"yn done echo"ok,youinputthecorrectanswer."
執行:
[[email protected]2_shell]$chmodu+x6_test.sh [[email protected]2_shell]$./6_test.sh pleaseinputyes/YEStostopthisprogram:e pleaseinputyes/YEStostopthisprogram:e pleaseinputyes/YEStostopthisprogram:yes ok,youinputthecorrectanswer.
until程式碼:
sum=0 i=0 until[$i-gt100] do if((i%2==0));then letsum+=i fi: leti++ done echo$sum
執行:
[[email protected]2_shell]$./6_test.sh 2550 程式碼: s=0 i=0 while["$i"!="100"] do i=$(($i+1)) s=$(($s+$i)) done echo"sumof1+2+3+...+100is:$s"
執行:
[[email protected]2_shell]$./7_test.sh sumof1+2+3+...+100is:5050
for ... do... done(固定迴圈)
for var in con1 con2 con3 ...
do
程式段
done
程式碼:
foranimalindogcatelephant do echo"thereare${animal}s..." done 執行: [[email protected]2_shell]$./8_test.sh therearedogs... therearecats... thereareelephants...
程式碼:
users=$(cut-d':'-f1/etc/passwd) forusernamein$users do id$username done
執行:
[[email protected]2_shell]$./9_test.sh uid=0(root)gid=0(root)組=0(root) uid=1(bin)gid=1(bin)組=1(bin),2(daemon),3(sys) uid=2(daemon)gid=2(daemon)組=2(daemon),1(bin),4(adm),7(lp) uid=3(adm)gid=4(adm)組=4(adm),3(sys) uid=4(lp)gid=7(lp)組=7(lp) uid=5(sync)gid=0(root)組=0(root)
測ip程式碼:
read-p"enterlike192.168.1->"network forsitenuin$(seq1100) do ping-c1-w1${network}.${sitenu}&>/dev/null&&result=0||result=1 if["$result"==0];then echo"server${network}.${sitenu}isup." else echo"server${network}.${sitenu}isdown" fi done
執行:
[[email protected]2_shell]$./9_test.sh enterlike192.168.1->192.168.174 server192.168.174.1isup. server192.168.174.2isup. server192.168.174.3isdown server192.168.174.4isdown server192.168.174.5isdown server192.168.174.6isdown server192.168.174.7isdown
程式碼:
#!/bin/bash read-p"pleaseinputadiretory:"dir if["$dir"==""-o!-d"$dir"];then echo"then$dirisnotexistinyoursystem." exit1 fi filelist=$(ls$dir) forfilenamein$filelist do perm="" test-r"$dir/$filename"&&perm="$permreadable" test-w"$dir/$filename"&&perm="$permwritable" test-x"$dir/$filename"&&perm="$permexecutable" echo"thefile$dir/$filename'spermissionis$perm" done
執行:
[[email protected]2_shell]$./10_test.sh pleaseinputadiretory:../1_shell thefile../1_shell/2'spermissionisreadablewritable thefile../1_shell/3'spermissionisreadablewritable thefile../1_shell/sh_1.sh'spermissionisreadablewritable thefile../1_shell/sh_2.sh'spermissionisreadablewritableexecutable
for ....do...done 的數值處理
for ((初始值; 限制值;執行步階))
do
程式段
done
這種寫法 適合在數值運算中
程式碼:
read-p"pleaseinputanumber.Iwillcountfor1+2+3+...+your_input"num s=0 for((i=1;i<=$num;i++)) do ((s+=i)) done echo"theresultof'1+2+3+...+$num'is$s"
執行:
[[email protected]2_shell]$./11_test.sh pleaseinputanumber.Iwillcountfor1+2+3+...+your_input10 theresultof'1+2+3+...+10'is55 程式碼: #!/bin/bash foriin{A..b} do echo"valis:$i" done
執行:
[[email protected]2_shell]$sh14_test.sh valis:A valis:B valis:C valis:D valis:E valis:F valis:G valis:H valis:I valis:J valis:K valis:L valis:M valis:N valis:O valis:P valis:Q valis:R valis:S valis:T valis:U valis:V valis:W valis:X valis:Y valis:Z valis:[ valis: valis:] valis:^ valis:_ valis:` valis:a valis:b
shell script 的 追蹤 與 debug
-n : 不執行script,僅查詢語法錯誤
-v: 在執行script之前,現將script的內容輸出到螢幕上
-x: 將使用到的script內容顯示到螢幕上
程式碼:
檢查是否有語法問題 沒有問題就什麼也不輸出
執行:
[[email protected] 2_shell]$ sh -n 12_test.sh
[[email protected] 2_shell]$
程式碼:
將使用到的程式碼顯示出來
執行:
[[email protected]2_shell]$sh-x12_test.sh +val=10 +str=hello +test10-eq10-ahello==hello +echo0 0 +test10-eq10 +testhello==hello +echo0 0
一是在命令列提供引數
$ sh -x ./script.sh
二是在指令碼開頭提供引數
#! /bin/sh -x
第三種方法是在指令碼中用 set命令啟用或禁用引數
set -x和set +x 分別表示啟用和禁用 -x引數 ,這樣可以只對指令碼中的某一段進行跟蹤除錯。
程式碼:
val=10 str="hello" set-x test$val-eq10-a"$str"=="hello" echo$? set+x test$val-eq10&&test"$str"=="hello" echo$?
執行:
[[email protected]2_shell]$sh-x12_test.sh +val=10 +str=hello +set-x +test10-eq10-ahello==hello +echo0 0 +set+x 0
:是一個特殊的命令,稱為空命令 ,該命令不做任何事,但 Exit Status總是真。此外 ,也可以執 行
/bin/true或 /bin/false得到真或假的 Exit Status。
檔名替換
這些用於匹配的字元稱為萬用字元 (Wildcard),具體如下 :
萬用字元 * : 匹配 0個或多個 任意字元
? : 匹配 一個任意 字元
[若干字元 ] : 匹配 方括號中任意一個字元的一次出現
執行: [[email protected]1_shell]$ls* 23sh_1.shsh_2.sh [[email protected]1_shell]$lssh_?.sh sh_1.shsh_2.sh [[email protected]1_shell]$ls[s]h* sh_1.shsh_2.sh
注意, Globbing 所匹配的檔名是由 Shell展開的 ,也就是說在引數還沒傳給程式之前已經展開
了 ,不是ls展開的
命令代換:
由反引號``括起來的也是一條命令 ,Shell先執行該命令 ,然後將輸出結果立刻代換到當前命令列
中。
[[email protected]1_shell]$DATE='date' [[email protected]1_shell]$echo$DATE date [[email protected]1_shell]$DATE=`date` [[email protected]1_shell]$echo$DATE 2016年08月21日星期日11:05:13CST
例如定義一個變數存放 date命令的輸出 :
命令代換也可以用 $()表示 : $ DATE=$(date)
[[email protected]1_shell]$DATE=$(date) [[email protected]1_shell]$echo$DATE 2016年08月21日星期日11:05:56CST
算術代換 :$(())
用於算術計算 ,$(())中的 Shell變數取值將轉換成整數 ,例如 :
[[email protected]1_shell]$v=3 [[email protected]1_shell]$echo$((v+3)) 6
$(())中只能用+-*/ 和()運算子 ,並且只能做整數運算。
(( )) 中間支援c語言的寫法
[[email protected]1_shell]$i=1;((i++));echo$i 2 [[email protected]1_shell]$i=1;((i+=5));echo$i 6 [[email protected]1_shell]$i=1;((i>0));echo$? 0 [[email protected]1_shell]$i=1;((i<0));echo$? 1
shell進度條小程式
程式碼:
#!/bin/bash functionproc() { i=0; str='' arr=('|''/''-''\\') index=0 while[$i-le100] #while((i<=100)) do printf"[%-100s][%d%%][%c]\r""$str""$i""${arr[$index]}" #這裡不用像c語言一樣fflush重新整理輸出緩衝區因為printf是子程序執行 #子程序退出自動重新整理 str=${str}'#' sleep0.1 leti++ letindex++ letindex%=4 #((index%=4)) done printf"\n" } functionmain() { proc } main
執行:
[[email protected]4_shell]$shproc.sh #########################################################################][74%][-]
讀取檔案資料 計算最大和最小值、平均值
程式碼:
#找 檔案中的最大值和 最小值
max=0 min=0 count=0 sum=0 whilereadline do if["$count"-eq"0"];then max=$line min=$line letcount++ letsum+=$line continue fi ["$max"-lt"$line"]&&max=$line ["$min"-gt"$line"]&&min=$line letsum+=$line letcount++ done<file echo$max echo$min echo"ibase=10;scale=2;$sum/$count"|bc
資料:
[[email protected]4_shell]$catfile 1 2 3 4 5 6 7 8 9
執行:
[[email protected]4_shell]$sh./5_shell.sh 9 1 5.00
建議數字計算 用(()) 不用[ ] []對於空資料報錯
如資料第四行空
file [[email protected]4_shell]$catfile 1 2 3 5 6 7 8 9
(())結果
if((line<9));then [[email protected]4_shell]$vimtest.sh [[email protected]4_shell]$sh./test.sh 1 2 3 5 6 7 8 error
[]結果 if [ "$line" -lt "9" ];then
[[email protected]4_shell]$sh./test.sh 1 2 3 ./test.sh:line11:((:<9:syntaxerror:operandexpected(errortokenis"<9") error 5 6 7 8 error
陣列
1 陣列的定義
一對()表示陣列 陣列元素用 空格 符號作為分隔符
[[email protected]4_shell]$a=(12345) [[email protected]4_shell]$echo$a 1 [[email protected]4_shell]$echo${a[*]} 12345 [[email protected]4_shell]$str=('q'"nihao"'hello') [[email protected]4_shell]$echo$str q [[email protected]4_shell]$echo${str[@]} qnihaohello
2 陣列的讀取與賦值(下標從0開始)
賦值:
[[email protected]4_shell]$a[10]=10
讀取:
[[email protected]4_shell]$echo${a[*]} 1234510
[[email protected]4_shell]$echo${a[@]} 1234510
得到長度:
得到整個陣列長度
[[email protected]4_shell]$echo${#a[*]} 6 [[email protected]4_shell]$echo${#a[@]} 6
得到陣列某個元素的長度
[[email protected]4_shell]$a=(1234510) [[email protected]4_shell]$echo${a[@]} 1234510 [[email protected]4_shell]$echo${#a[5]} 2 [[email protected]4_shell]$echo${#a[0]} 1
刪除:
[[email protected]4_shell]$echo${a[@]} 1234510
#刪除某個元素
[[email protected]4_shell]$unseta[2] [[email protected]4_shell]$echo${a[@]} 124510
#刪除整個陣列
[[email protected]4_shell]$unseta [[email protected]4_shell]$echo${a[@]} [[email protected]4_shell]$
3.特殊使用:
分片:
$[陣列名{@或*]起始位置:長度} 從起始位置開始 切長度個元素
返回的是字串 中間用空格隔開
所以如果加上"()" , 將的到切片的陣列。
[[email protected]4_shell]$echo${a[@]} 123456 [[email protected]4_shell]$echo${a[@]:0:3} 123 [[email protected]4_shell]$echo${a[@]:2:3} 345 [[email protected]4_shell]$echo${a[@]:2:5} 3456 [[email protected]4_shell]$echo${a[@]:1:5} 23456
加上"()" , 將的到切片的陣列。
[[email protected]4_shell]$echo${a[@]:1:5} 23456 [[email protected]4_shell]$newa=(${a[@]:1:5}) [[email protected]4_shell]$echo${newa[@]} 23456
替換:
呼叫方法是: ${陣列名[@或*]/查詢字元/替換字元} 該操作不會改變原先的內容, 如果需要修改, 可以像上面一樣 加() 生成一個新的陣列
[[email protected]4_shell]$a=(123456) [[email protected]4_shell]$echo${a[@]} 123456 [[email protected]4_shell]$echo${a[@]/3/100} 12100456 [[email protected]4_shell]$echo${a[@]} 123456
原內容 未改變
要改變原內容 加()
[[email protected]4_shell]$a=(${a[@]/3/100}) [[email protected]4_shell]$echo${a[@]} 12100456 [[email protected]4_shell]$str=("nihao"hello) [[email protected]4_shell]$echo${str[@]} nihaohello [[email protected]4_shell]$echo${str[@]/ni/wo} wohaohello [[email protected]4_shell]$str=("nihao""hello""here") [[email protected]4_shell]$echo${str[@]} nihaohellohere [[email protected]4_shell]$echo${str[@]/he/the} nihaothellothere
遍歷陣列:
arr=(aaabbbcccddd) num=${#arr[@]} for((i=0;i<num;i++)) { echo${arr[i]} } [[email protected]4_shell]$sharr.sh aaa bbb ccc ddd
特殊
arr=(aaabbbcccddd) arr[50]="ffff" num=${#arr[*]} for((i=0;i<num;i++)) { echo${arr[i]} }
結果 多了一個元素arr[50] 讀也是讀五個 只不過是從前向後讀 沒有讀到arr[50] 讀到空
這裡${#arr[*]}和 ${#arr[@]}都是5
[[email protected]4_shell]$sharr.sh aaa bbb ccc ddd [[email protected]4_shell]$catarr.sh
下面這種方式解決讀到空的問題 沒有讀到後面的有效數字
程式碼:
arr=(aaabbbcccddd) arr[50]="ffff" num=${#arr[*]} forvarin${arr[*]} #forvarin${arr[@]}這兩個效果一樣都能訪問到定義了的資料 { echo$var }
執行:
[[email protected]4_shell]$sharr.sh aaa bbb ccc ddd ffff
[[email protected]4_shell]$forvarin${arr[*]};doecho$var;leti++;done a b c hello [[email protected]4_shell]$arr[100]="iam100" [[email protected]4_shell]$forvarin${arr[*]};doecho$var;leti++;done a b c hello iam100 [[email protected]4_shell]$[[email protected]4_shell]$forvarin${arr[*]};doecho$var;leti++;done a b c hello [[email protected]4_shell]$arr[100]="iam100" [[email protected]4_shell]$forvarin${arr[*]};doecho$var;leti++;done a b c hello iam100 [[email protected]4_shell]$forvarin${arr[@]};doecho$var;leti++;done a b c hello iam100 [[email protected]4_shell]$i=0;while((i<${#arr[*]}));doecho${arr[i]};leti++;done a b c hello [[email protected]4_shell]$i=0;while((i<${#arr[@]}));doecho${arr[i]};leti++;done a b c hello [[email protected]4_shell]$ ${arr[@]};doecho$var;leti++;done a b c hello iam100 [[email protected]4_shell]$i=0;while((i<${#arr[*]}));doecho${arr[i]};leti++;done a b c hello [[email protected]4_shell]$i=0;while((i<${#arr[@]}));doecho${arr[i]};leti++;done a b c hello [[email protected]4_shell]$
從這個 例子可以看出
for var in種方式訪問的是 有效元素的個數
for ((i = 0; i < len;i++)) 是從前向後找 ,找len個就停止,後面隔著的有些有效的資料就沒有輸出
count=0; while [ $count -le 100] touch test${count};
數學運算(( ))中變數直接取得是 變數的值
v1=1
v2=2
((v3 = v1 + v2)) // (($v3 = $v1 + $v2)) 也可以
echo $(v3)
echo $(arr[*]) 顯示所有的元素 (空的丟棄)
echo $(arr[@]) 顯示所有的元素
echo $(#arr[@]) 顯示 已經定義的元素的個數 如 arr
遍歷陣列
for i in $(arr[@])
do
echo $(arr[i])
done
單引號 雙引號
單引號 對轉義、特殊的變數 都不會 進行處理 原樣輸出
雙引號 會處理
[[email protected] 1_shell]$ /bin/bash sh_1.sh
10
\$ \\ $myint \"
###############
$ \ 10 "
轉載於:https://blog.51cto.com/alick/1841148