Shell Script Basics
Shell Script 快速參考筆記,從 Shell 的概念講起,整理 pwd、ls、chmod、find 等常用指令,並涵蓋變數、條件判斷、迴圈、函式與導向運作子等腳本基礎。
Shell 是什麼
一台電腦的組成到運行可以想像成有硬體組成(Hardware),核心(Kernel),以及殼層(Shell)。 那麼使用者所接觸到的就是殼層這部分,這一圈可能有 CLI(command-line interface)或 GUI(Graphical user interface),就如同我們所使用的 terminal 或者任何圖形化介面等。
而 Shell script 就是我們透過殼層與內核溝通的語言,藉由殼層翻譯給內核,內核再去驅動我們硬體做出相對應指令。
那為什麼我們要了解這項語言呢? 主要是我們很多自動化動作可以藉由 Shell script 來達成,簡單的就是開機時,系統內的 Shell 初始電腦硬碟,開始調用 CPU 以及 Memory 輸出畫面到我們螢幕上。
另一個例子像是 Hexo 在搭建部落格時,有時候我會先用hexo server --draft來查看剛寫好的文章排版,但要先執行 clean 以及 generate 的動作,前後雖然只有 3 個指令,但有時校稿 n 次,那麼我就要執行 n*3 次的指令輸入。
因此簡化的方式就是寫一個 bash,讓我開啟本端伺服器時不需要輸入那麼多指令並且等待。
#!/bin/sh
echo "Opening server"
hexo clean
hexo g
hexo server --draftBasics
當你 Google Shell script,網路上已經有很多寫好的文章,而這篇文章想要濃縮其精華,做成一篇 QRG(Quick Reference Guide)。
Basic of the basic commands
在真正開始有 scripting 之前,先了解一些組成單元,也就是基本操作,會這些操作之後就只是把指令串接起來而已。
pwd
The pwd utility writes the absolute pathname of the current working directory to the standard output. pwd 會將當前位置做出 output 到終端機上。
ls
ls 會將當前位置的檔案列出。 常見的當配為ls -a來顯示出隱藏的檔案及資料夾,ls -R遞迴全部底下檔案。
du
Disk usage. 列出底下檔案大小。
常見搭配為du -h為 human-readable,後啜會加上單位方便判讀; du -s會將符合的當作一個 entry,不會往下去做顯示,也等同於-d 0做 depth = 0 的意思。
另一個是挑檔案大小du -t [number],如果數值為正數,那麼大於這個數值的檔案會顯示出來,如果數值為負數,那麼小於這數值的檔案會被顯示出來。
cd
change directory,這中文我也不知道叫什麼😂,就是更換你的位置。
單純cd會跳回 user 的資料夾底下,cd [directory]會切換到底下 directory 的位置,cd ..會回到上一層。
在使用cd時,可以一連串往下走,也就是cd first/second/third,每按下tab就會 autosuggest 以及顯示出當前有的 entry。
man
當不知道指令如何使用時,呼叫man [command]就會跳出該指令的 mannual 囉。
top
類似工作管理員,監控目前的程式資源消耗。
top -o [key]以 key 為主降序排列,top -user [username]查看某使用者的程序。
mkdir
make directory,新建資料夾。
touch
touch – change file access and modification times 對於更改時間,其實更常用來建立新檔案,
touch [filename.extension]。
chmod
chmod – change file modes or Access Control Lists
改變檔案的 mode 或檔案存取權限。一個檔案可以被使用者(user)、群組(group)、其他(others)做出讀取(r)、寫入(w)、執行(x)。
chmod我分成兩種方式,implicitly 以及 explicitly.
Explicitly 即是把目標對象以及權限寫清楚,chmod u=rwx即是使用者可以有讀取、寫入並且執行的權限。
又或者chmod g=u-x代表群組等同於使用者權限但扣除執行的權限。
Implicitly 則是用數字來表示權限等級,並且依照 ugo 的順序。
chmod 744即是給予使用者全部權限,其餘只有讀取的權限。
| 讀取 Read | 寫入 Write | 執行 Execute |
|---|---|---|
| 4 | 3 | 1 |
echo
echo就如同print或printf,將字串輸出至終端。
sudo
以 super user 的權限執行指令。
在某些場合下,指令可能需要最高權限來執行,sudo [command]就會以超級使用者來跑,但為了電腦安全,通常會跳出需要輸入電腦密碼以確保安全。
cat
The cat utility reads files sequentially, writing them to the standard output.
cat會將檔案內容輸出至終端,可以當作類似預覽功能。
mv
移動檔案或更改檔名。
mv [file1] [file2]或mv [file] [directory]
cp
複製檔案,如同mv寫法
find
如同英文,尋找目標檔案。
find . -empty 會找尋當前底下所有空白檔案。
find . -name "*.fits" -exec rm -rf {} \; 找尋底下所有副檔名為fits的檔案,並且執行rm -rf,也就是刪除檔案。
find / -type d找尋家目錄底下所有為目錄的位置。
find . -size 2k找尋檔案大小等於 2kb。size 可以使用+-來表示大於小於,e.g., -size +20M -size -5G在 20MB 到 5GB 這範圍。
tree
list contents of directories in a tree-like format.
以樹狀圖表示底下檔案分佈,以我其中一個 ios 專案來舉例:
.
├── LICENSE
├── MyPlayground.playground
│ ├── Contents.swift
│ ├── contents.xcplayground
│ └── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ └── tyler.xcuserdatad
│ └── UserInterfaceState.xcuserstate
├── README.md
└── YesSir
├── YesSir
│ ├── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── MainScreen.swift
│ ├── Models
│ │ ├── Company.swift
│ │ ├── CompanyView.swift
│ │ ├── Squad.swift
│ │ ├── SquadCard.swift
│ │ ├── SquadView.swift
│ │ └── TrainerIcon.swift
│ ├── Preview\ Content
│ │ └── Preview\ Assets.xcassets
│ │ └── Contents.json
│ ├── YesSirApp.swift
│ └── rollcall.swift
└── YesSir.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ └── xcuserdata
│ └── tyler.xcuserdatad
│ └── UserInterfaceState.xcuserstate
└── xcuserdata
└── tyler.xcuserdatad
└── xcschemes
└── xcschememanagement.plist
21 directories, 24 files常見的選項是tree -L 2,Level 如同 Depth,決定往下的深度。tree -d只顯示目錄。
nohup
這項指令通常在如果要跑的指令很久,要將東西放在伺服器上跑時,避免使用者登出後程式停止執行。
nohup [command] &,這裡的&是將指令放在背景執行。
通常我習慣加上>將輸出資訊導到我要的檔案,i.e.,nohup [command] [args] > log.txt &
Scripts
第一行開頭會用 Shebang 或稱 Hashbang,由#!所組成的宣告,代表著我們接下來要使用哪個直譯器執行底下指令,後面接的路徑你可以藉由which bash來查詢。
比如我的就是寫#!/bin/bash
Variable
要注意 assign 變數時,等號左右不可空格。
Var="Tyler", echo "My name is $Var"
Input
讀取 input 使用read,其寫法可以直接read [Var]或帶有提示文字read -p [Text] [Var]
if
if [condition]
then
action
else
action
fiif [condition]
then
action
elif [condition2]
then
action
else
action
ficase
read -p "Are you 21 or over? Y/N " ANSWER
case "$ANSWER" in
[yY] | [yY][eE][sS])
echo "You can have a beer :)"
;;
[nN] | [nN][oO])
echo "Sorry, no drinking"
;;
*)
echo "Please enter y/yes or n/no"
;;
esacfor loop
FILES=$(ls *.txt)
NEW="new"
for FILE in $FILES
do
echo "Renaming $FILE to new-$FILE"
mv $FILE $NEW-$FILE
donewhile loop
LINE=1
while read -r CURRENT_LINE
do
echo "$LINE: $CURRENT_LINE"
((LINE++))
done < "./new-1.txt"function
function greet() {
echo "Hello, I am $1 and I am $2"
}Control operators
;semi-colon 會讓前一個指令結束後,接著跑下一個指令。command1 ; command2&會讓指令在背景處理。command1 &&&意同 and, 如果前一個指令完成,那麼第二個指令才會運作。command1 && command2||意同 or, 如果前一個指令失敗,那麼第二個指令才會運作。command1 || command2|這會將第一個指令的輸出傳到下一個指令當作輸入,形成 pipeline,又稱 pipe operator.command1 | command2
Redirection operators
<給予 command inputcommand < file,檔案會以讀取模式打開。<>如同<,但檔案會以讀取寫入打開。>將指令回傳值輸出到檔案中。command > log.txt>|如同>,但會覆寫檔案。>>如同>,但會以附加方式寫進檔案。
Summary
這小短篇算是把常用實用的指令給涵括,還有很多指令沒提到,但我想這些指令大概夠我碩士畢業了😂 在 shell script 上也許會有另一篇 advance 的筆記)?
References
導向運作子 Shell script 個人筆記 「程式筆記」Shell Script 簡易筆記 Shell Scripting Crash Course - Beginner Level