# Shell基礎 > 寫Shell的路上,不孤單,有電腦會陪伴我們 ## 基礎 :::spoiler 第一站:Hello World ```bash= #!/bin/bash echo "Hello World" ``` * `#!/bin/bash`:告訴系統該用哪個編譯 * `echo "Hello World"`:類似print,在終端印出文本訊息 ::: :::spoiler 第二站:特殊字元 1. `#`註釋 2. `;`命令分隔符(一行可以有多個命令,前面要空格) 3. `;;`條件語句終止符(case專用的,後續會介紹) 4. `:`空命令,類似true(總是返回退出狀態0,且不執行操作) 5. `$`取值符號,取出變量內容 6. `()`命令組,裡面的變量算是區域變數,父shell不可見 ::: :::spoiler 第三站:特殊字符『-』part1 ```bash= (cd /usr/src && tar cf - . ) | (cd /usr/dst && tar xpvf -) ``` * `cd /usr/src`:這一段代表到此目錄下 * `&&`:前一段執行成功才執行下一段 * `tar cf - .` : 將目錄下所有(.)壓縮成標準輸出(-)因為有`|`所以將輸出給下一個命令 * `tar xpvf -`:解壓縮來自標準輸入的資料(-) * 本腳本主要將src目錄下所有檔案及資料夾搬移到dst ::: :::spoiler 第四站:特殊字符『-』part2 ```bash= #!/bin/bash BACKUPFILE=backup-$(date +%m-%d-%Y) archive=${1:-$BACKUPFILE} tar cvf - `find . -mtime -1 -type f -print` > $archive.tar gzip $archive.tar echo "Directory $PWD backed up in archive file \"$archive.tar.gz\"." exit 0 ``` * `BACKUPFILE=backup-$(date +%m-%d-%Y)`:命名變數,以日期命名 * `archive=${1:-$BACKUPFILE}`:如果沒有在指令中特別命名,則用預設 * `tar cvf - find . -mtime -1 -type f -print > $archive.tar`:找到過去一天內有更動的檔案(非資料夾)進行壓縮成tar檔 * `-mtime n`:n天前 * `-mtime -1`:1天內 * `-mtime +1`:超過1天 * `-type f`:檔案 * `-type d`:資料夾 ::: :::spoiler 第五站:變量與參數 * `不要混淆 = 與 -eq,後者用來進行比較而非賦值。` * `一個未被賦值或未初始化的變數擁有空值(null value)。注意:null值不等同於0。` * `''`:單引號完全不解析包覆的內容 * `""`:雙引號會展開變數命令及特殊(換行)符號等 * 變量替換 ```bash= a=375 hello=$a #hello取a得值 echo hello #不加 $,會直接印出字串:hello echo $hello #會展開變數 hello 的值,也就是:375 echo ${hello} #與上面相同,使用花括號可更清楚變數邊界:375 echo "$hello" #加雙引號也會展開變數值:375 echo "${hello}" #同上,雙引號+花括號:375 echo hello="A B C D" echo $hello #沒有引號,bash 會把空格當作參數分隔,結果是:A B C D(多餘空格被壓縮) echo "$hello" #有雙引號,整個字串會被當作一個單位保留空格:A B C D echo echo '$hello' #單引號不會展開變數,會原樣輸出:$hello ``` --- * 變量賦值 ```bash= #!/bin/bash a=879 #這時候a是字串 echo "The value of \"a\" is $a." let a=16+5 #這時bash會當a為整數做加法處理 echo "The value of \"a\" is now $a." echo echo -n "Values of \"a\" in the loop are: " for a in 7 8 9 11 do echo -n "$a " done echo echo -n "Enter \"a\" " read a #這時候a讀取輸入的值 echo "The value of \"a\" is now $a." exit 0 ``` * `這裡補充弱型態,在Bash中,變量始終以字符串儲存,但在使用let或(())等數學運算方法時,會被解析為數字,使用 declare -i 可使其在進行賦值等操作時視為整數,並可透過 unset 清除型態設定。` ::: :::spoiler 第六站:弱型態與特殊變量 * Bash弱型態 * 儲存上永遠是字串型態的內容 * 透過計算可以將變數(暫時視為整數) * 透過declare -i 可強制將變數未來的賦值行為視為整數 * 在數學運算中空值視為 0 * unset會清除該變數,從記憶體拔掉 * 環境變量(導出) ```bash= export 變數名稱 #export將變量標記為環境變量,可被子進程繼承,並在當前 Shell 環境中生效 ``` * 位置参数 * `$0`:腳本名稱`$n`:開始為第n個參數(10以後要加{$10}) ```bash= args=$# # 取得參數的個數(位置參數個數),例如傳入 3 個參數,args 就是 3 lastarg=${!args} # 使用間接參照,取得最後一個參數的值 ``` ::: :::spoiler 第七站:測試:part1 ```bash= if [...] fi ``` * `[`是 test 命令,根據括號內的條件判斷結果。當只有單個字符串時,非空字符串(如 [ "0" ]、[ "xyz" ])為 true,空字符串(如 [ "" ] 或未宣告的變量 [ $a ])為 false。其他用法包括數值比較(如 -eq)、字符串比較(如 =)、文件測試(如 -f)等。 * `if [0]`:為true,0為字串 * `if [-1]`:為true,-1為字串 * `if []`:為false,為空字串 * 未宣告的情況`if [$a]`:為false,空值 ```bash= if [...]; then #if和then在同一行要用;分開 #elif = else if ``` * `if [ 條件 ]`:括號內為test語法,裡面塞條件判斷 * `-eq`:等於 `-ne`:不等於 * `-lt`:小於 `-le`:小於等於 * `-ge`:大於 `-ge`:大於等於 * 以上陳列出數字比較,另有檔案及邏輯的條件判斷 * `[[]]`:雙括號內有更多的使用彈性(bash)內部數值比較會直接轉換8&16進位後再比 * `(())`:此運算出來的結果與`[]`相反,為真(非0)⇒ exit status 為 0,為假則是 1 * `(( 0 ))`:1 * `(( 1 ))`:0 * `(( 5 > 4 ))`:0 * `(( 5 > 9 ))`:1 ::: :::spoiler 第八站:測試:part2 * `[[]]`:這個在做比較時,需要空白[[ a > b ]] * `(())`:這個只做運算比較,不用空白((a>b)) * 文件測試部分陳列~語法`[ -e a.file ]` * `-e`:文件是否存在 * `-f`:是否為常規文件(非目錄) * `-s`:文件大小不為0 * `-d`:是否為目錄 * `-r`:是否可讀`-w`:可寫`-x`:可執行 * `f1 -nt f2`:f1比f2新 * `f1 -ot f2`:f1比f2舊 * 邏輯比較 * `-a`:AND運算 * `-o`:OR運算 * 範例~`[ "$a" -gt 0 -a "$b" -gt 0 ]`ab均大於0的話 * 邏輯比較補充 * `&&`:這個AND運算要在`[[]]`裡面使用 * `||`:這個OR運算要在`[[]]`裡面使用 ::: :::spoiler 第九站:運算符 * 運算大致與程式語言相同 * `&`和`|`:都是做算術運算的,會轉為二進制去做 * `&&`和`||`:這兩個才是邏輯判斷的,小心弄錯 * `^`:這個是XOR運算,**沒有XOR邏輯判斷**`^^` * `!`:邏輯運算NOT * 特殊運算符`,` * `$((1+1,a=2*2,3/3))` * 每段都會計算,`echo $a`會印4 * `$`取值會取最後一個3/3的答案1 * 數字運算符 * `0數字`:8進位 * `0x數字`:16進位 * `let "a = 進制#數字"`:轉譯成十進位a ::: --- 下一站 :[Shell 進階](https://hackmd.io/a1Pm_wSlRmaKcmji61DiJg)
×
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