1. 程式人生 > >Shell 編程基礎(二)

Shell 編程基礎(二)

shell 編程基礎(二)

shift 參數向左移一位

shift + 數字,參數一次向左移N位

編程的時候可以用來判斷後面還有幾個參數

當shift後值為空的時候,返回錯誤

使用read來把輸入值分配給一個或多個shell變量

read 從標準輸入中讀取值,給每個單詞分配一個變量

所有剩余單詞都被分配給最後一個變量


bash如何展開命令行

按以下優先級順序

把命令行分成單個命令詞

展開別名

展開大括號的聲明({})

展開波浪符聲明(~)

命令替換$() 和 ``

再次把命令行分成命令詞

展開文件通配(*、 ?、 [abc]等等)

準備I/0重導向(<、 >)

運行命令


轉義

反斜線(\)會使隨後的字符按原意解釋

$ echo Your cost: \$5.00

Your cost: $5.00

加引號來防止擴展

? 單引號(’)防止所有擴展

? 雙引號(”)也防止所有擴展,但是以下情況例外:

$(美元符號) - 變量擴展

`(反引號) - 命令替換

\(反斜線) - 禁止單個字符擴展

!(嘆號) - 歷史命令替換


環境配置相關

bash的配置文件

按生效範圍劃分,存在兩類:

全局配置:

/etc/profile

/etc/profile.d/*.sh

/etc/bashrc

個人配置:

~/.bash_profile

~/.bashrc


配置文件的生效順序與範圍

交互式登錄:

(1)直接通過終端輸入賬號密碼登錄

(2)使用“ su - UserName” 切換的用戶

執行順序:/etc/profile --> /etc/profile.d/*.sh -->~/.bash_profile --> ~/.bashrc --> /etc/bashrc

? 非交互式登錄:

(1)su UserName

(2)圖形界面下打開的終端

(3)執行腳本

(4)任何其它的bash實例

執行順序: ~/.bashrc --> /etc/bashrc -->/etc/profile.d/*.sh

Profile類

? 按功能劃分,存在兩類:

profile類和bashrc類

? profile類:為交互式登錄的shell提供配置

全局:/etc/profile, /etc/profile.d/*.sh

個人:~/.bash_profile

功用:

(1) 用於定義環境變量

(2) 運行命令或腳本

bashrc類

? bashrc類:為非交互式和交互式登錄的shell提供配置

全局:/etc/bashrc

個人:~/.bashrc

功用:

(1) 定義命令別名和函數

(2) 定義本地變量

編輯配置文件生效

? 修改profile和bashrc文件後需生效

兩種方法:

1重新啟動shell進程

2 . 或source

例:

. ~/.bashrc

bash 退出任務

? 保存在~/.bash_logout文件中(用戶)

? 在退出登錄shell時運行

? 用於

創建自動備份

清除臨時文件


$-變量

? h:hashall,打開這個選項後,Shell 會將命令所在的路徑hash下來,避免每次都要查詢。通過set +h將h選項關閉

? i:interactive-comments,包含這個選項說明當前的 shell是一個交互式的 shell。所謂的交互式shell,在腳本中,i選項是關閉的。

? m:monitor,打開監控模式,就可以通過Job control來控制

進程的停止、繼續,後臺或者前臺執行等。

? B:braceexpand,大括號擴展

? H:history,H選項打開,可以展開歷史列表中的命令,可以

通過!感嘆號來完成,例如“!!”返回上最近的一個歷史命令,

“!n”返回第 n 個歷史命令



$* 與$@的區別

$*

以下是a.sh的腳本代碼:

技術分享圖片技術分享圖片

以下是b.sh的腳本代碼

技術分享圖片技術分享圖片

看到了吧,$*把所有參數當成了一個整體,所以b.sh的第一個參數就是a b c,後面的參數就是為空了

技術分享圖片技術分享圖片


$@

由於跟以上演示只是相差了一點,將b.sh調用變成$@

技術分享圖片技術分享圖片

看到了吧,$@把所有參數當成了獨立的個體,所以b.sh的各個參數就是a.sh一樣了。

技術分享圖片技術分享圖片


shift作用演示

以下為腳本內容:

echo "這個腳本的名字是:`basename $0`"

echo "第一個參數是:$1"

echo "第二個參數是:$2"

echo "第三個參數是:$3"

echo "演示下shift參數調整功能,這裏只是一次一個,shift後面可以接具體數字的"

shift

echo "第一個參數是原來的\$2參數:$1"

echo "第二個參數是原來的\$3參數:$2"

echo "第三個參數是原來的\$3之後的參數,因為是沒有,應該是空的:$3"

技術分享圖片技術分享圖片


邏輯運算

true =1 false =0

與運算

1與1 為1

只要有0就為0

或運算

只要有1就為1

0與0 為0

! 0 為1

! 1 為 0


shell編程中的短路運算

短路與

第一個為0,結果必定為0

第一個為1,第二個必須要參與運算

比如:

命令1 && 命令2

當命令1返回值為0,也就是的時候,命令2必須參與運算

當命令1返回值為1,也就是的時候,命令2不會參與運算


短路或

第一個為1,結果必定為1

第一個為0,第二個必須要參與運算

比如:

命令1 || 命令2

當命令1返回值為1,也就是的時候,命令2必須參與運算

當命令1返回值為0,也就是的時候,命令2不會參與運算


異或:^

異或的兩個值,相同為假,不同為真

比如:

命令1 ^ 命令2

當命令1和命令2返回值都相同的時候,得出的就是假

當命令1和命令2返回值不相同的時候,得出的就是真

看以下例子,操作符位置不一樣,結果就不一樣了,為什麽第一條會同時顯示2條信息呢?

技術分享圖片技術分享圖片


第一條指令集返回狀態是這麽解讀的:第一條命令查找不到用戶,返回值為非0,假,因此將會執行||這後的命令並且輸出成功,返回值為0,真,因此就會執行&&之後的命令,並且成功輸出並且返回值為0.

所以會顯示出2條信息。

第二條指令集返回狀態是這麽解讀的:第一條命令查找不到用戶,返回值為非0,假,與後面是與的關系,後面不管是真假,最終的結果都是假了,所以會執行||之後的命令並且輸出成功,返回值為0

下圖我們故意把echo輸入錯誤,變成echoa,這樣,這一條指令就會返回為非0,假

技術分享圖片技術分享圖片


指令集返回狀態是這麽解讀的:第一條命令查找到用戶,返回值為0,真,因此會執行後面的指令,可是後面的指令是錯誤的命令,會返回非0,假,與後面的指令是或的關系,它必須執行,輸出成功,返回值為0


特殊運算結果產生的坑

expr 和let命令計算的時候,要註意

expr 計算的結果是null或0的時候,$?返回的值為1

技術分享圖片技術分享圖片


let計算的時候,最後一個參數為0的時候,返回值為1

技術分享圖片技術分享圖片


中括號可以用來判斷變量是否為空,請仔細觀察以下變化。中括號內的變量記得用雙引號

技術分享圖片技術分享圖片

也可以使用一個字符+變量來組合判斷變量是否會空

技術分享圖片技術分享圖片


雙中括號裏一些使用規範

[[ "$var" == "abc" ]] 判斷2邊字符串是否相等時,使用==

[[ "$var" =~ \.sh$ ]] 當使用=~擴展正則表達式時,表達式不需要帶引號

如果是在比較字符串的時候,==後面加引號表過的是字符串,不加引號表示的是通配符,因此,這種情況比較容易搞蒙自己。那麽建議是這樣的:只有涉及到需要使用正則表達式的時候才使用雙括號。

技術分享圖片技術分享圖片


BUG

以下是bash的一個BUG了哦,只要在正則表達式裏面出現了反斜線,就會導致匹配失敗,因此,解決方案就是把正則表達式內容用變量代替。

技術分享圖片技術分享圖片

技術分享圖片技術分享圖片


以下是2個不同的案例對比技術分享圖片技術分享圖片


來個簡單點的正則吧

技術分享圖片技術分享圖片


測試條件時

-v 變量名 檢查變量是否已經設置

Centos 6 是不支持 -v

技術分享圖片技術分享圖片

num="";[ -v num ] && echo "設置" || echo "未設置"

技術分享圖片技術分享圖片


Centos 7

技術分享圖片技術分享圖片

num="";[ -v num ] && echo "設置" || echo "未設置"

技術分享圖片技術分享圖片


分組

linux中shell的小括號、大括號的用法區別

小括號()

①命令組。括號中的命令新開一個子shell程序,括號中的變量為本地變量 ,不能夠在腳本其他部分使用。括號中多個命令之間用分號隔開。

②命令替換。命令替換$(cmd)等同於`cmd`(這不是單引號,`是ESC下面的那個鍵) ,shell執行過程中發現了$(cmd)結構,便將$(cmd)中的cmd執行一次,得到其輸出,再將此輸出放到原來命令。例如:

技術分享圖片技術分享圖片

這是一個實例,如果沒有加上小括號的時候,cd /app/dir/ 後,再執行pwd可以看到確實是進入了目錄,但是當括號內的pwd命令執行完之後,命令提示符顯示的就是/app,也就是cd命令前的目錄。因為cd命令是作用在子進程了。在實際中的應用場景的話,就是臨時開啟一個子進程執行一些操作而不影響當前環境

技術分享圖片技術分享圖片

③用於初始化數組。如:arr=(m n)


大括號 { }

①拓展。對大括號中的文件名做擴展。在大括號中,不允許有空白,除非這個空白被引用或轉義。拓展分為普通以逗號(,)進行拓展,如echo {a,b}.txt將間隔的各項內容均列出;以兩個點(..)進行拓展,如echo {1..5}.txt自動補全1到5中間內容。

# echo {a,b}.txt

a.txt b.txt

# echo {1..5}.txt

1.txt 2.txt 3.txt 4.txt 5.txt

②內部組 。與小括號中的命令不同,大括號內的命令在當前shell運行,不會重新開子shell。括號內的命令間用分號隔開,最後一個命令後必須跟分號。{}的第一個命令和左括號之間必須要有一個空格。

在Shell中的小括號,大括號結構和有括號的變量,命令的用法如下:

1.${var}

2.$(cmd)

3.()和{}

4.${var:-string},${var:+string},${var:=string},${var:?string}

5.$((exp))

6.$(var%pattern),$(var%%pattern),$(var#pattern),$(var##pattern)

現在來一一詳細介紹:

1)Shell中變量的原形

這個最常見的變量形式就是$var,打印var用命令

echo $var

可是這裏有個問題:當你要顯示變量值加隨意的字符(如$varAA)時,就會出錯。系統會認為整個varAA是一個變量,這時就可以用一個大括號來限定變量名稱的範圍,如${var}AA,這樣就好了。

技術分享圖片技術分享圖片

技術分享圖片技術分享圖片

此時正是使用 {大括號} 的時候了

技術分享圖片技術分享圖片


2)命令替換$(cmd)

命令替換$(cmd)和符號`cmd`(註意這不是單引號,在美式鍵盤上,`是ESC下面的那個鍵)有相同之處.以echo$(ls)來說明整個替換過程:shell掃描一遍命令行,發現了$(cmd)結構,便將$(cmd)中的cmd執行一次,得到其標準輸出,再將此輸出放到原來命令echo $(ls)中的$(ls)位置,即替換了$(ls),再執行echo命令。如下:


3)一串的命令執行()和{}


()和{}都是對一串的命令進行執行,但有所區別:


A, ()只是對一串命令重新開一個子shell進行執行

B, {}對一串命令在當前shell執行

C, ()和{}都是把一串的命令放在括號裏面,並且命令之間用;號隔開

D, ()最後一個命令可以不用分號

E, {}最後一個命令要用分號

F, {}的第一個命令和左括號之間必須要有一個空格

G, ()裏的各命令不必和括號有空格

H, ()和{}中括號裏面的某個命令的重定向只影響該命令,但括號外的重定向則影響到括號裏的所有 命令


Shell 編程基礎(二)