1. 程式人生 > 實用技巧 >shell 指令碼-符號-基礎語法

shell 指令碼-符號-基礎語法

為了便於識別 建議 以.sh 結尾

shell指令碼 可以放上所有的命令列的指令(源於bash)

shell指令碼 是 解釋型語言 c/c++ 是編譯型語言

下面用到的 shell程式碼sh_1.sh

#!/bin/bash
cd../
ls
pwd

解釋型指令碼的執行過程:

script.sh 是文字檔案,根本沒有程式碼段和 _start 函式 , exec 怎麼執行。

解釋:

Shellfork 一個子程序並呼叫 exec執行 ./script.sh這個程式,exec 系統呼叫應該把子程序的程式碼

段替換成./script.sh程式的程式碼段 ,並從它的 _start開始執行。然而 script.sh是個文字檔案

,根 本

沒有程式碼段和 _start函式 ,怎麼辦呢 ?其實 exec還有另外一種機制 ,如果要執行的是一個文字文

, 並且第一行用 Shebang 指定了直譯器 ,則用 直譯器程式的程式碼段替換當前程序 ,並且從解釋

器 的_start開始執行 ,而這個文字檔案被當作命令列引數傳給直譯器 。因此, 執行上述指令碼相

當於執 行程式

wKiom1e6tZagpKxfAAFq0WZtcj0114.png

1. 互動 Shell(bash)fork/exec一個子 Shell(sh)用於執行指令碼 ,父程序 bash等待子程序 sh終止。

2. sh讀取指令碼中的 cd ..命令 ,呼叫相應的函式 執行內建命令 ,改變當前工作目錄為上一級

目 錄。

3. sh讀取指令碼中的 ls

命令 ,fork/exec這個程式 ,列出當前工作目錄下的檔案 ,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 ..

命令改變的是子ShellPWD,不會影響到 互動式Shell1(對於檔案sh, 互動式shell1會先建立一個子shell2,子shell2會再建立一個shell3,shell3遇見cd命令 會直接由shell2執行,改變的是shell2的路徑,shell1的路徑不變)

然而source ./script.sh 和 . ./script.sh 方式

則有不同的效果,cd ..命令是直接在互動式Shell1下執行,改變互動ShellPWD

對於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 -xset +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