# MIT-Missing Semester Lecture 2: Shell Tools and Scripting (2020) > 課程影片:[英文字幕](https://www.youtube.com/playlist?list=PLyzOVJj3bHQuloKGG59rS43e29ro7I57J) / [中文字幕](https://space.bilibili.com/518734451/channel/seriesdetail?sid=3320015) / [課程其他資源中文版](https://missing-semester-cn.github.io/) ## ■ shell腳本 ■ ### ▋ 賦予變數、訪問變數值`($)` ``` foo=bar echo $foo //輸出bar ```  值得注意的點: 使用bash時,空格相當重要,主要是因為空格式用來分隔參數的符號,所以如果輸入`foo = bar`就會無法作用。 ``` foo = bar ```  ### ▋ 雙引號、單引號 在單純字串中,單雙引號並不會有影響、差別,以下方為例。 ``` echo "Hello" //輸出Hello echo 'World' //輸出World ```  但如果我們會用到「變數」,那麼使用單雙引號就會有差別了,如下所示,可以發現單引號包住變數的話,輸出時並不會幫忙轉譯,只有在雙引號之下的變數才成功被轉議程變數的值"bar"。 ``` foo=bar echo "Value is $foo." //輸出 Value is bar. echo 'Value is $foo.' //輸出 Value is $foo. ```  ### ▋ 定義function(利用vim建立、source指令定義) 在bash之中,你除了可以像一般程式語言一樣寫一些for loop、while loop等等外,最重要的是你還可以定義函數。 #### ▋ 利用vim建立 我們可以在終端上進入我們定義的函數: ``` vim mcd.sh ```  他會進到vim編輯器中  按下i、a 或 o 這三個鍵其中一個進入 Insert 模式(如下圖),才能開始打字。之後我們輸入以下內容: ``` mcd () { mkdir -p "$1" cd "$1" } ```  上面的程式碼代表著一個mcd函式會執行哪些內容,他會先利用mkdir建立資料夾,而 `$1`代表腳本或函式獲取的第一個參數,接著進入腳本或函式獲取的第一個參數資料夾中。 bash使用了大量特殊變數來表示參數,錯誤碼與其他相關變數,可以參考[Advanced Bash-Scripting Guide:Chapter 3. Special Characters](https://tldp.org/LDP/abs/html/special-chars.html)。 以下為一些較常見的參數:  那定義好該函式之後,我們可以先按下 ESC 鍵或是 Ctrl + `[` 組合鍵,可退回至 Normal 模式。  接著輸入 :w ,按下enter會進行存檔。  之後輸入:q ,按下enter會關閉這個檔案,當然也可以直接輸入 :wq 進行存檔並關閉檔案。 #### ▋ source指令定義 建立好這個函式之後,我們要輸入以下內容,在shell中定義mcd函式。 ``` source mcd.sh ```  接著,我們就能利用mcd函式了,可以看出執行mcd後,確實幫我們建立了一個名為"whatMatterYouWantToCall"的資料夾,並且cd進入該資料夾中。 ```! mcd whatMatterYouWantToCall //whatMatterYouWantToCall 是參數,該參數會傳入我們先前打的"$1" ```   ### ▋ 特殊變數 shell中使用了大量特殊變數來表示參數,錯誤碼與其他相關變數,可以參考[Advanced Bash-Scripting Guide:Chapter 3. Special Characters](https://tldp.org/LDP/abs/html/special-chars.html)。  #### ▋ 特殊變數: !! bang bang 這裡尤其提到變數"!!"(bang bang <--很可愛的名字),輸入`sudo !!`按下enter之後,他會完整的出現上一條指令(可能上一條指令因為權限錯誤導致失敗),這個時候利用`sudo !!`重新執行一次,也因為擁有sudo權限,所以這一次會請你輸入密碼,並且可以正確的執行原本想執行的指令。 #### ▋ 特殊變數: `$?` `$?`是一個錯誤代碼,他可以告訴你上一段執行的指令中的錯誤,以下為範例。 ``` echo "Hello" //輸出Hello,並沒有任何問題 echo $? //輸出0,代表沒有錯誤 ```  接著我們嘗試執行一段有錯誤的代碼,我們想在先前創建的mcd函式中尋找一個變數名為"foobar"(但是根本沒有這個變數嘛,所以心裡肯定早有得到錯誤的答案)。 ```! grep foobar mcd.sh //在先前創建的mcd函式中尋找一個變數名為"foobar" echo $? //輸出1,因為上方出錯了,他根本找不到foobar ```  而我們也可以從`$?`知道true以及false各自默認錯誤代碼為0跟1。 ``` true echo $? //輸出0 false echo $? //輸出1 ```  ### ▋ 邏輯運算子: || && 再來是邏輯運算子的部份,我覺得跟JavaScript的Logical Operator概念差不多。 可以參考[MDN的Logical operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_operators#logical_operators)或者前幾天念React時有讀到的[11-182. Conditional Rendering](https://hackmd.io/@noz915/Skc_aHtyp#11-182-Conditional-Rendering)。 #### ▋ 邏輯運算子: || or(||),會回傳第一個為truthy value的內容。 ``` false || echo "Oops fail" //輸出Oops fail ```  ``` true || echo "Will be not be printed" //會直接回傳true,所以不會再執行後方的statement ```  #### ▋ 邏輯運算子: && and(&&),會回傳第一個為falsy value的內容或者回傳最後一個為truthy value的內容。 ``` true && echo "Things went well" ```  ``` false && echo "This will not print" //會直接回傳false,不會再執行後方的statement ```  ### ▋ 指令替換(command substitution) :`$()` 使用 $( pwd ) 時, pwd 會被執行,然後用它的執行結果替換掉 $( pwd ) ,以下為範例。 ``` foo=$(pwd) echo $foo //輸出pwd執行後的內容,也就是印出當前所在位置 ```  所以結合前面的利用雙引號包住`$(pwd)`,將`$(pwd)`做轉譯,如下範例。 ``` echo "We are in $(pwd)." ```  ### 接著我們再利用vim創建一個`example.sh`,並在裡頭輸入以下內容: ```c! #!/bin/bash echo "Starting program at $(date)" # date將會被替代為日期與時間 echo "Running program $0 with $# arguments with pid $$" # $0是我們目前正在執行的腳本 # $#是我們給該命令的參數數量 # $$是正在運行該命令的process ID(又稱PID) for file in "$@"; do # $@是全部參數 grep foobar "$file" > /dev/null 2> /dev/null # /dev/null被稱為黑洞文件 # >是作為輸出的重新定向 # 2>則是作為「錯誤」的輸出重新定向 # 當字串沒有被找到,grep將會退出並返回狀態碼 1 # 我們將標準輸出流(STDOUT)和標準錯誤流(STDERR)重新導向到Null,因為我們並不關心這些訊息 if [[ $? -ne 0 ]]; then # -ne為not equal為一個比較運算子 echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi done ```  接著執行`example.sh`,並在後方給予三個參數`mcd.sh`, `script.py`, `example.sh`。 ``` source example.sh mcd.sh script.py example.sh ```  然後因為先前創立的`mcd.sh`裡並沒有foobar這個變數,所以經過執行`example.sh`後,他會幫`mcd.sh`最後面加上註腳`#foobar`。  **** ## ■ 習題與解答 ■ 投影片:[Merge-Sort](https://docs.google.com/presentation/d/1_ssQLGKDk6IchOB0QBIqKYrQi2S_pq_sQfKN9ttY2qg/edit?usp=sharing)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up