linux shell程式設計 bash的奇技淫巧

2022-04-05 11:32:32 字數 4226 閱讀 5883

本文主要講bash指令碼中容易出錯和很少用但是用起來有意想不到效果的部分。

正常的for迴圈:

for i in

a b c 1 2 3; do

echo"$i

"done

數字序列迴圈:

for i in `seq

100`; do

echo"$i

"done

其中的 `seq

100` 也可以換成 

的這種形式可以表示連續的數列,可以從小到大也可以從大到小,但是可惜不像python的range()那樣可以指定間隔量

c語言風格的for迴圈:

for (( i=1; i<100; i++ )); do

echo"$i

"done

for迴圈會使用空格、換行符、製表符分割文字,依次迭代,如:

a="

ab cd

ef"for i in

$a;

doecho

"$i"

done

輸出結果:

ab

cdef

shell分割文字其實是以乙個全域性變數$ifs為依據的,預設情況下ifs=$'\n\t '(即換行符、製表符、空格),可以通過修改ifs的值來改變迭代文字的分割方式。

請注意上面的$a如果加引號括起來的話,會把它當成乙個整體,不會切割迭代。

雙括號「(())」還可以用於數學計算:

(( a=123+456

))echo$a#

579

在雙括號中,變數並不需要用$符號來引用,英文單詞天然是變數。

a=b

b=100

echo $

#100

效果等同於 eval echo \$$a

包含特殊字元的字串:

echo

"ab\ncd

"

上列命令會輸出字元ab+換行+cd,但是實際上字串"ab\ncd"中並不包含「換行」這個字元,輸出的換行只是echo命令解析的結果。

# a="

ab\ncd"#

echo

"length of var a is $

"length of var a is

6

通過$的形式可以得到乙個字串的長度,上面示例可以看出來,字串"ab\ncd"的長度是6而不是預期的5。

那麼能否將不可列印的字元賦值給變數呢?答案是肯定的:

# a=$'

\x61\n\x62'#

echo"$a

"ab

請注意一定用的是單引號「'」,用雙引號括起來是不起轉義作用的。

變數值字元擷取:

a="

abcdefg

"echo $

#cdefg

echo $

# cde

變數值字元刪除:(#為從頭部開始匹配,%為從尾部匹配,支援萬用字元「?*」)

a="

abdcdefgh

"echo $ # 刪除字串頭部匹配「*d」的部分,萬用字元*代表匹配任意多個字元,乙個#號代表萬用字元「*」保守匹配

#cdefgh

echo $ # 兩個#號表示貪婪匹配

#efgh

echo $ # 同上,兩個%時代表貪婪匹配

# abdc

a=b

b="abcdefg

"echo"$

"# defg

可以同時支援間接引用和字元刪除

用於賦值前檢查是否已經定義或賦值。

unset a

unset b

b=""

# a沒有定義,b定義了但是空值

echo $  # 如果沒定義,則表示式採用預設值789

#789

echo $ # 如果沒定義或是空值,則表示式採用預設值789

#789

echo $ # 如果沒定義,則表示式採用預設值789,b定義了

#echo $ # 如果沒定義或是空值,則表示式採用預設值789

#789

echo

$a # 原變數並沒有被賦值

#echo

$b # 原變數並沒有被賦值

#b=123

echo $ # 如果變數已經被賦值,則不改變原有值

#123

unset a

echo $ # 如果a沒定義,則表示式採用預設值,並給a賦值

#789

echo$a#

789# a已經被賦值了

a=""

echo $

#echo $ # 加冒號:的作用和之前一樣

#789

echo$a#

789

前面講了用「-」和「=」的,還有一種用「+」的,用於當變數已經被賦值的情況下採用預設值,舉一反三,不贅述了。

$0是檔名,$#代表引數個數,$1,$2等等表示執行該指令碼或函式後面跟的位置引數,$1代表第乙個引數,依次類推,需要注意的是,第9個以後的引數應該這麼表示:

$

這表示第10個引數,必須用花括號括起來,否則就變成第1個變數後面加個字元「0」了。因為這個有的人以為第9個以後的位置變數就不可用了,是錯的。

$@和$*都表示所有的變數,但是區別是前者將每個作為乙個字串,是多個字串的結合,而後者將所有變數組合成乙個字串,用空格分隔。

這樣不同會在for迴圈裡面造成使用的區別,在for迴圈裡面,如果加上引號 for i in"$@

" 和 for i in"$*

" 是不同的,前者還是會依次把引數代入迴圈,而後者會吧所有引數作為字串一次性代入:

echo

'for i in"$@

"; do

echo"$i

"done

for i in"$*

"; do

echo"$i

"done

'> myscript.sh

chmod

755 myscript.sh

./myscript.sh abc 123

def

結果是:

abc

123def

abc

123 def

那麼$@加引號和不加引號有區別麼?

大部分情況下結果看起來是一樣的,但會在某些情況下造成麻煩,因為for迴圈會用換行符「\n」和空格來拆分變數,所以如果呼叫指令碼所帶的引數中帶有空格或者換行符,不加引號的時候會把這個引數拆開了依次代入,而加了引號就可以避免這種情況。

echo

'for i in"$@

"; do

echo"$i

"done

for i in $@ ; do

echo"$i

"done

'> myscript.sh

chmod

755 myscript.sh

./myscript.sh abc "

123 def

"

結果是:

abc

123def

abc123

def

將陣列的值依次代入迴圈,可以用$和$這兩種方法,區別和加引號的區別同上面位置引數的使用相同。

shell的字串匹配通常是這樣的:

[ "

abc" = "

abc"

]echo $?

# 0

$? 這個變數代表上條命令的返回碼。若字串相同則返回0,否則返回1。除了全匹配外,通過雙方括號「」還可以用正規表示式匹配

[[ "

abc234def

" =~ ^abc[0-9][a-z]+$ ]]

echo $?

# 0

注意這裡正規表示式不能用引號括起來,而且只支援基本的正則,不支援如「\b \s」之類的擴充套件。

另單方括號『[ ]』和雙方括號『[[ ]]』的區別,單括號等同於bash內建test命令,雙方括號不是命令,是bash關鍵字。

linux shell 程式設計

bin bash comments your commands go here 首行中的符號 告訴系統其後路徑所指定的程式bash即是解釋此指令碼檔案的shell程式。除第一行外,以 開頭的行就是注釋行,直到此行的結束。如果一行未完成,可以在行尾加上 這個符號表明下一行與此行會合併為同一行。有環境變...

linux shell 程式設計

1 程式設計入門 shell的簡介。從程式設計師的角度來看,shell本身是一種用c語言編寫的程式,從使用者的角度來看,shell是使用者與linux作業系統溝通的橋梁。使用者既可以輸入命令執行,又可以利用 shell指令碼程式設計,完成更加複雜的操作。在linux gui日益完善的今天,在系統管理...

Linux Shell 程式設計

檔案描述 shell 代號 dev stdin 標準輸入,一般指的是鍵盤輸入 dev stdout 標準輸出,一般指終端顯示器 dev stderr 標準錯誤,一般指終端顯示器 l輸出重定向 l輸入重定向 l追加重定向 l錯誤重定向 2 l輸出和錯誤同時重定向 應用例子 1.將 ls的結果輸出到檔案...