<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
shell英文翻譯過來是外殼的意思,作為計算機語言來理解可以認為它是作業系統的外殼。我們可以通過shell命令來操作和控制作業系統,比如Linux中的shell命令就包括ls
、cd
、pwd
等等。
shell是站在核心的基礎上編寫的一個應用程式,它連線了使用者和Linux核心,從而讓使用者能夠更加便捷、高效、安全的使用linux核心,這其實就是shell的本質。
使用專業術語的說法來解釋,Shell其實是一個命令直譯器,它通過接受使用者輸入的Shell命令來啟動、暫停、停止程式的執行或對計算機進行控制。
shell指令碼就是由Shell命令組成的執行檔案,將一些命令整合到一個檔案中,進行處理業務邏輯,指令碼不用編譯即可執行。它通過直譯器解釋執行,所以速度相對來說比較慢。
我們在1.2中也解釋道shell指令碼其實就是shell命令組成的檔案,shell指令碼可以記錄命令執行的過程和執行邏輯,以便以後重複執行,還可以批次、定時處理主機,方便管理員進行設定或者管理。
在建立shell指令碼時,我們預設新建一個以.sh
/.script
結尾的檔案,主要是為了讓程式設計師更加快捷的辨認出該檔案是一個shell指令碼檔案。
我們建立一個test.sh
的shell指令碼檔案,其中具體內容為下:
#!/bin/bash echo hello
- " # ”開頭的就是註釋,單行註釋
- <<EOF … EOF 或 :<<! … ! :多行註釋
- #!/bin/bash : 主要用於指定直譯器
- Linux中提供的shell直譯器有:
- /bin/sh
- /bin/bash
- /usr/bin/sh
- /usr/bin/bash
我們根據指令碼檔案是否具有可執行許可權,將執行一個shell指令碼的方法分為兩大類。
這種情況下我們有三種方式來執行指令碼:
手動在環境中開啟指定直譯器:sh test.sh
直接在當前環境中執行的shell中執行指令碼:. test.sh
直接在當前環境中執行的shell中執行指令碼:source test.sh
在這一部分由於我們假設指令碼檔案有可執行器許可權,所以我們使用chmod +x test.sh
為我們的test.sh
檔案增加了可執行許可權。
我們知道當一個檔案具有可執行許可權時我們可以使用該檔案的路徑名直接執行該檔案,有兩種方式可以執行指令碼:
1.絕對路徑名執行指令碼檔案
絕對路徑就是從根目錄下開始記錄檔案路徑名,是檔案在計算機上真正存在的路徑。(如果不知道你的檔案路徑名,可以在當前位置的shell中使用pwd
查詢當前所在位置)
2../相對路徑名的格式執行指令碼檔案
相對路徑是指以當前的檔案作為起點,相較於當前目錄的位置而被指向並且加以參照的檔案資源。
比如我們知道test.sh
檔案的絕對路徑為/home/westos/Desktop/textcpp/test.sh
,那麼當我們在testcpp資料夾中時,test.sh
檔案的相對路徑為test.sh
。
又因為.
代表當前所在位置,故而為其實./test.sh
其實就是該檔案的絕對路徑,只是表示的方式不同。
變數名其實就是一片記憶體區域的地址或者可以說是定址符號,有了變數我們就可以使用一串固定的字元來表示不固定的目標。
在shell中會同時存在三種型別變數。
3.1.3.1 字串變數的建立
3.1.3.2 拼接字串
str02=`date`"end"
3.1.3.3 獲取字串長度
1.使用wc -L
命令
wc -L
可以獲取到當前行的長度,因此對於單獨行的字串可以用這個簡單的方法獲取,另外wc -l
則是獲取當前字串內容的行數。
echo "abc" |wc -L
2.使用expr length
可以獲取string的長度
expr length ${<!--{C}%3C!%2D%2D%20%2D%2D%3E-->str}
3.awk獲取域的個數
但是如果大於10個字元的長度時是否存在問題需要後面確認
echo "abc" |awk -F "" '{print NF}'
4.通過awk+length
的方式獲取字串長度
echo 「Alex」|awk '{print length($0)}'
5.通過echo ${#name}
的方式
name=Alex echo ${#name}
3.1.3.4 提取子字串
1.如下方式:
程式碼 | 意義 |
---|---|
${varible##*string} | 從左向右擷取最後一個string後的字串 |
${varible#*string} | 從左向右擷取第一個string後的字串 |
${varible%%string*} | 從右向左擷取最後一個string後的字串 |
${varible%string*} | 從右向左擷取第一個string後的字串 |
例,如下程式碼:
$ MYVAR=foodforthought.jpg $ echo ${MYVAR##*fo}
執行結果為rthought.jpg
2.使用${varible:n1:n2}
擷取變數varible從n1到n2之間的字串,可以根據特定字元偏移和長度,來選擇特定子字串,如下程式碼:
$ EXCLAIM=cowabunga $ echo ${EXCLAIM:0:3}
執行結果最終顯示cow
。
如果說變數是儲存單個變數的記憶體空間,那麼陣列就是多個變數的集合,它儲存多個元素在一片連續的記憶體空間中。在bash中,只支援一維陣列,不支援多維陣列。
3.1.3.1 陣列定義與參照
定義一個陣列方式如下:
陣列名=(元素1 元素2 元素3 ... 元素n)
指定陣列對應下標的元素進行賦值:
陣列名[下標]=值
同時指定多個陣列元素進行賦值:
陣列名=([下標1]=值1 [下標2]=值2 ... [下標n]=值n)
參照陣列對應下標的元素:
${陣列名[下標]}
3.1.3.2 遍歷陣列元素
使用for
(或while
迴圈)迴圈遍歷陣列元素:
#!/bin/bash a=(1 2 3 4 5 6) for((i=0; i<10; i++)) do echo "a[$i]=${a[$i]}" done
除此以外我們還可以使用${a[*]}
或者${a[@]}
來遍歷陣列元素,具體程式碼如下:
#!/bin/bash a=(1 2 3 4 5 6) echo ${a[*]} echo ${a[@]}
3.1.3.3 獲取陣列長度
我們可以使用#
來獲取陣列長度,需要注意的是在shell指令碼中我們越界存取陣列時是不會報錯的。
#!/bin/bash a=(1 2 3 4 5 6) echo ${a[*]} echo "a len: ${#a[*]}"
我們先使用其獲取陣列中的元素後使用#
獲取元素個數即可。
3.1.3.4 合併陣列
我們可以如下進行拼接:
#!/bin/bash a=(1 2 3 4 5 6) b=("hello" "zhaixue.cc") c=(${a[*]} ${b[*]})
這樣我們就將兩個陣列拼接起來了。
3.1.3.5 刪除陣列元素
如果我們想要刪除某個陣列元素,具體程式碼如下:
#!/bin/bash a=(1 2 3 4 5 6) echo ${a[*]} echo "a len: ${#a[*]}" unset a[5] echo ${a[*]} echo "a len: ${#a[*]}"
執行結果如下:
我們如果要刪除整個陣列,可以執行unset a
,舉例程式碼如下:
#!/bin/bash a=(1 2 3 4 5 6) echo ${a[*]} echo "a len: ${#a[*]}" unset a echo ${a[*]} echo "a len: ${#a[*]}"
相關的變數含義為:
變數 | 含義 |
---|---|
$0 | 代表執行的檔名 |
$1 | 代表傳入的第1個引數 |
$n | 代表傳入的第n個引數 |
$# | 引數個數 |
$* | 以一個單字串顯示所有向指令碼傳遞的引數。 |
$@ | 與$*相同,但是使用時加引號,並在引號中返回每個引數 |
$$ | 指令碼執行的當前程序號 |
$! | 後臺執行的最後一個程序的ID |
$? | 顯示最後命令的退出狀態。0表示沒有錯誤,其他任何值表明有錯誤。 |
原生的bash並不支援簡單的數學運算,通常要通過其它命令來實現。
以下表格中的a
和b
都是變數。
運算 | shell中格式 |
---|---|
加法 | expr $a + $b |
減法 | expr $a - $b |
乘法 | expr $a * $b |
除法 | expr $b / $a |
取餘 | expr $b % $a |
賦值 | a=$b |
相等 | [ $a == $b ] |
不相等 | [ $a != $b ] |
需注意:
條件表法式需要放在方括號之間,並且要有空格。使用expr
進行計算時需要使用反引號,為了讓讀者更容易理解,給出下列範例程式碼。
#!/bin/bash a=10 b=20 val=`expr $a + $b` echo "a + b : $val"
關係運算子只支援數位,不支援字串,除非字串的值是數位。
運算 | shell中的實現 | 主要符號 |
---|---|---|
檢測兩個數是否相等 | [ $a -eq $b ] | -eq |
檢測兩個數是否不相等 | [ $a -ne $b ] | -ne |
檢測左邊的數是否大於右邊的 | [ $a -gt $b ] | -gt |
檢測左邊的數是否小於右邊的 | [ $a -lt $b ] | -lt |
檢測左邊的數是否大於等於右邊的 | [ $a -ge $b ] | -ge |
檢測左邊的數是否小於等於右邊的 | [ $a -le $b ] | -le |
舉例程式碼如下:
#!/bin/bash a=1 b=2 if [ $a != $b ] then echo "$a != $b : a 不等於 b" else echo "$a == $b: a 等於 b"
執行結果如下:
具體如下:
運算 | shell中的實現 | 主要符號 |
---|---|---|
非運算 | [ ! false ] | ! |
或運算 | [ $a -lt 20 -o $b -gt 100 ] | -o |
與運算 | [ $a -lt 20 -a $b -gt 100 ] | -a |
具體如下:
運算 | shell中的實現 | 主要符號 |
---|---|---|
邏輯的 AND | [[ $a -lt 100 && $b -gt 100 ]] | && |
邏輯的 OR | [[ $a -lt 100 || $b -gt 100 ]] | || |
布林運運算元和邏輯運運算元的區別:
語法上,邏輯運算需要雙括弧,布林運算只需要單大括弧功能上,邏輯運算具有特殊的短路功能,即是在AND運算中第一個表示式為false時則不執行第二個表示式,在OR運算中第一個表示式為true時不執行第二個表示式。
下表列出了常用的字串運運算元:
運算 | shell中的實現 | 主要符號 |
---|---|---|
檢測兩個字串是否相等 | [ $a = $b ] | = |
檢測兩個字串是否不相等 | [ $a != $b ] | != |
檢測字串長度是否為0 | [ -z $a ] | -z |
檢測字串長度是否不為 0 | [ -n “$a” ] | -n |
檢測字串是否為空 | [ $a ] | $ |
主要用於檢測unix檔案的各種屬性:
運算 | shell中的實現 | 主要符號 |
---|---|---|
檢測檔案是否是塊裝置檔案 | [ -b $file ] | -b file |
檢測檔案是否是字元裝置檔案 | [ -c $file ] | -c file |
檢測檔案是否是目錄 | [ -d $file ] | -d file |
檢測檔案是否是普通檔案(既不是目錄,也不是裝置檔案) | [ -f $file ] 返回 true | -f file |
檢測檔案是否設定了 SGID 位 | [ -g $file ] | -g file |
檢測檔案是否設定了粘著位(Sticky Bit) | [ -k $file ] | -k file |
檢測檔案是否是有名管道 | [ -p $file ] | -p file |
檢測檔案是否設定了 SUID 位 | [ -u $file ] | -u file |
檢測檔案是否可讀 | [ -r $file ] | -r file |
檢測檔案是否可寫 | [ -w $file ] | -w file |
檢測檔案是否可執行 | [ -x $file ] | -x file |
檢測檔案是否為空(檔案大小是否大於0) | [ -s $file ] | -s file |
檢測檔案(包括目錄)是否存在 | [ -e $file ] | -e file |
舉例如下:
#!/bin/bash file="/home/westos/Desktop/textcpp/test.sh" if [ -r $file ] then echo "檔案可讀" else echo "檔案不可讀" fi
執行結果為:
1.(( ))
我們可以直接使用雙圓括弧計算其中的內容,如((var=a+b)),該指令經常在if/while等條件判斷中需要計算時使用。
2.let
在計算表示式的時候我們可以直接使用let,如let var=a+b。
3.expr
在前面的內容中我們也提到了它,是非常常用的計算指令,使用時需要在外部增反引號
var=`expr a+b`
4.bc計算器
bc計算器支援shell中的小數進行運算,並且可以互動式或者非互動式的使用。基本使用方式為var=$(echo "(1.1+2.1)"|bc)
;
5.$[]
我們可以直接使用這種方式計算中括弧中的內容,如echo $[1+2]
和其他語句不同,shell的流傳呢個控制不可為空。接下來我們為大家介紹sehll中常用的語法。
3.3.1.1 if-fi
就類似於c中的if條件判斷,如下:
if condition then command1 command2 ... commandN fi
3.3.1.2 if-else-fi
程式碼如下:
if condition then command1 else command2 fi
若condition成立則執行command1,否則執行command2。
3.3.1.3 if else-if else
程式碼如下:
if condition1 then command1 elif condition2 then command2 else command3 fi
若condition1成立,執行command1,若condition1不成立,condition2成立執行command2,若兩個condition都不成立就執行command3。
3.3.2.1 for迴圈
格式為:
for var in item1 item2 ... itemN do command1 command2 ... commandN done
以上也可以寫做一行,若變數var
在列表中,則for迴圈執行一次所有命令。以以下程式碼作為測試:
#!/bin/bash for loop in 1 2 3 4 5 do echo "The value is: $loop" done
執行結果為:
3.3.2.2 while迴圈
格式如下:
while condition do command done
我們執行如下程式碼:
#!/bin/bash int=1 while(( $int<=5 )) do echo $int let "int++" done
執行的最終結果為:
3.3.2.3 無限迴圈
我們可以以上兩種語句給出無限迴圈的實現,首先看一下for迴圈如何實現:
for (( ; ; ))
除此以外我們也可以使用while迴圈實現如下:
while : do command done
或者直接將while中的判斷語句置為真:
while true do command done
3.3.2.4 until迴圈
until 迴圈執行一系列命令直至條件為 true 時停止。語法格式如下:
until condition do command done
3.3.2.5 跳出迴圈
在迴圈過程中,有時候需要在未達到迴圈結束條件時強制跳出迴圈,Shell使用兩個命令來實現該功能:break
和continue
。
1.break跳出迴圈
當我們需要跳出當前迴圈,或者終止死迴圈時,我們就可以使用break來跳出迴圈。接下來我們執行如下程式碼:
#!/bin/bash var=1 while(( $var < 5 )) do if(( $var>3 )) then echo "跳出迴圈" break fi echo "$var" var=`expr $var + 1` done
執行結果為:
在該回圈中var>3
時break,而是直接跳出迴圈。
2.continue跳出迴圈
continue命令與break命令類似,只有一點差別,它不會跳出所有迴圈,僅僅跳出當前迴圈。 接下來我們執行如下程式碼:
#!/bin/bash var=1 while(( $var < 5 )) do if(( $var>3 )) then echo "跳出迴圈" continue fi echo "$var" var=`expr $var + 1` done
執行結果為:
使用continue跳出的迴圈只是當前迴圈,無法跳出整個迴圈,由於在該程式碼中我們每次執行到continue就會跳出當前迴圈,無法執行 var=expr $var + 1
,所以迴圈條件一直成立,就成了死迴圈。
case ... esac
為多選擇語句,與其他語言中的switch ... case
語句類似,是一種多分支選擇結構,每個 case
分支用右圓括號開始,用兩個分號 ;;
表示 break,即執行結束,跳出整個 case … esac 語句,esac
(就是 case 反過來)作為結束標記。
case 要求取值後面必須為單詞 in,每一模式必須以右括號結束。取值可以為變數或常數,匹配發現取值符合某一模式後,其間所有命令開始執行直至 ;;。
若檢測匹配時無一匹配,使用*
捕獲該值,再執行後續命令。
語法格式如下:
case 值 in 模式1) command1 command2 ... commandN ;; 模式2) command1 command2 ... commandN ;; *) command1 esac
select in是shell中獨有的一種迴圈,非常適合終端的互動場景,它可以顯示出帶編號的選單,使用者出入不同編號就可以選擇不同的選單,並執行不同的功能。
語法格式如下:
select var in seq do action done
我們執行如下程式碼:
#!/bin/bash echo "What is your favourite OS?" select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do break; done echo "You have selected $var"
執行結果為:
函數其實就是將一段程式碼組合封裝在一起實現某個特定的功能或返回某個特定的值。我們在定義函數時需要先起一個函數名,在使用的時候直接呼叫函數名即可。
shell中定義函數格式如下:
[ function ] funname [()] { action; [return int;] }
注意:
1.以上的[ function ]
也可以省略
2.當函數沒有return時,預設返回最後一個命令的執行結果作為返回值。
在shell中,呼叫函數時可以向其傳遞引數。在函數內部直接通過$n
獲取引數的值。我們給出範例如下:
#!/bin/bash funWithParam(){ echo "第一個引數為 $1 !" echo "第十個引數為 ${10} !" } funWithParam 1 2 3 4 5 6 7 8 9 34 73
需要注意$10
不能返回第十個引數,當n>10
的時候,需要使用$(n)
來獲取引數。
Shell指令碼中執行函數時並不會開啟子程序,預設在函數外部或函數內部定義和使用變數的效果相同。函數外部的變數在函數內部可以直接呼叫,反之函數內部的變數也可以在函數外部直接呼叫。但是這樣會導致變數混淆、資料可能被錯誤地修改等等問題,那麼如何解決這些問題呢?
系統為我們提供了一個local語句,該語句可以使在函數內部定義的變數僅在函數內部有效。定義時直接在變數前加local
即可。
一個命令通常從一個叫標準輸入的地方讀取輸入,預設情況下,這恰好是你的終端。同樣,一個命令通常將其輸出寫入到標準輸出,預設情況下,這也是你的終端。
一般情況下,每個 Unix/Linux 命令執行時都會開啟三個檔案:
但有些時候我們可能需要將資料從其它檔案讀入或讀出,這就需要我們重定向。
我們可以讓命令從檔案中獲取,這樣本來的命令需要從標準輸入stdin
中獲取,轉換為從我們的指定檔案中獲取。這樣本來需要從鍵盤輸入的命令就會轉移到檔案讀取內容。語法如下:
command1 < file
同輸入重定向很相似,輸出重定向也是將本來需要輸出標準輸出檔案stdout
中轉化為我們的指定檔案中。語法如下:
command1 > file
我們可以直接藉助標準錯誤檔案的檔案描述符來重定向stderr
,語法如下:
$ command 2>file
擴充一點,如果我們想將stdout
標準輸出檔案和stderr
標準錯誤檔案合併重定向到一個指定檔案中,語法如下:
$ command > file 2>&1
Here Document 是 Shell 中的一種特殊的重定向方式,用來將輸入重定向到一個互動式 Shell 指令碼或程式。它的作用是將兩個 delimiter 之間的內容(document) 作為輸入傳遞給 command。基本語法如下:
command << delimiter documentdelimiter
注意:
結尾的delimiter 一定要頂格寫,前面不能有任何字元,後面也不能有任何字元,包括空格和 tab 縮排。開始的delimiter前後的空格會被忽略掉。
如果希望執行某個命令,但又不希望在螢幕上顯示輸出結果,那麼可以將輸出重定向到 /dev/null中,/dev/null 是一個特殊的檔案,寫入到它的內容都會被丟棄;如果嘗試從該檔案讀取內容,那麼什麼也讀不到。但是 /dev/null 檔案非常有用,將命令的輸出重定向到它,會起到"禁止輸出"的效果。語法如下:
$ command > /dev/null
到此這篇關於Shell指令碼的超詳細講解的文章就介紹到這了,更多相關Shell指令碼講解內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45