Shell 編程基礎(二)
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 編程基礎(二)