以 Unix-Like 的作業系統為例,shell 是介於使用者與 OS 之間的的交談介面。所有來自使用者的指令,都會被 shell 轉換為 OS 可以認得的命令並執行,相對的,OS 所回傳的內容自然也會被 shell 轉換為使用者可以辨識的訊息。
以下用一張簡單的圖來說明使用者、shell、OS 三者的關係:
shell 其中一個很重要的工作,就是將使用者所下達的指令,轉換為可以交由 OS 所執行的命令,以下用一個簡單的 command 為例:
shell> sort -n phonelist > phonelist.sorted以上指令的作用,在於將 phonelist 檔案中的內容,以數字大小進行排列後,輸出至檔案 phonelist.sorted 中。
而 shell 是如何將此段指令進行轉換呢? 它做了以下步驟:
- 將整段指令分解為「sort」、「-n」、「phonelist」、「>」、「phonelist.sorted」五個部分,每個部分皆稱為 word。
- 判斷每個 word 的目的為何:
「sort」是排序的指令、「-n」以及「phonelist」是參數、「>」以及「phonelist.sorted」被合在一起視為一個 I/O 的指令。 - 啟動一個 I/O 的動作,準備將內容寫入 phonelist.sorted 中。
- 開始將原檔案進行排序。
每個步驟的執行細節就不在這邊介紹,這裡只是要表達出 shell 在 parse 一個指令大概的流程為何。
bash 的特色與優點
在之後針對 shell 的介紹,都是以 bash 為主,因為它是目前最流行的 shell,功能也相對最為強大;而到底 bash 有哪些特色與優點呢? 以下有兩篇好文章,說明的相當詳細:
檔案
在 bash 中,檔案被分為三種,分別是純文字檔、執行檔(binary)、以及目錄(directory),其中目錄結構在學習 Linux 上是個相當重要的議題,不過這邊並不贅述,主要把重心放在 bash 上,而且盡量寫些大家容易忘記的部分。
所以像是符號「~」代表使用者家目錄,這種很基本的觀念,就不再多著墨了!
【備註】在 Unix-Like 的檔案系統,沒有所謂的「副檔名」,並非像 Windows 一樣,*.txt 代表純文字檔、*.exe 代表執行檔....等等,這是必須注意的!
1、檔案名稱與萬用字元
首先,要說明的是隱藏檔,在 Windows 中,隱藏檔是以檔案的屬性來決定;不過在 Linux 中,隱藏檔的檔名則是以「.」作為開頭。
接著介紹萬用字元(wildcard),基本的萬用字元有以下幾種:
萬用字元 | 符合的內容 |
? | 任何單一字元 |
* | 一個或多個任何字元 |
[set] | 符合[set]中設定的任何字元 |
[!set] | 不符合[set]中設定的任何字元 |
其中 ? 與 * 的差別就是符合單一字元或是多個字元而已,以下介紹 [set] 的用法:
[set] 描述 | 符合的內容 |
[abc] | a or b or c |
[.,;] | 句號 or 逗號 or 分號 |
[-_] | 減號 or 底線 |
[a-c] | a or b or c |
[a-z] | 任一小寫英文字母 |
[!0-9] | 任一非數字字元 |
[0-9!] | 任一數字 or 驚嘆號 |
[a-zA-Z] | 任一英文字母 |
[a-zA-Z0-9_-] | 任一英文字母 or 數字 or 底線 or 減號 |
以下用個簡單例子來說明,假設有兩個目錄 /home/user1 以及 /home/user2,想要一次把這兩個目錄列表出來,可以用下指令:
shell> ls /home/user*假如又要列出上述兩個目錄中,名稱為 a 或是 c 開頭的目錄或檔案,可用以下指令:
shell> ls /home/user*/[ac]*其他的應用,就是由使用者自行去發揮了!
2、Brace Expansion
在 bash 3.0 以後,提供了 Brace Expansion 的功能,它是以左右大括號來設定字元的篩選條件,的用法跟 wildcard 有點不太一樣,以下直接用範例來說明:
Brace Expansion | 符合的內容 |
b{ed,olt,ar}s | beds, bolts, bars |
b{ar{d,n,k},ed}s | bards, barns, baeks, beds |
{2..5} | 2 or 3 or 4 or 5 |
{d..h} | d or e or f or g or h |
輸入與輸出(I/O)
1、Standard I/O
所謂的 standard Input,可能是來自使用者的鍵盤、或是某個檔案內容; standard output 可能就是使用者的螢幕、印表機、或是其他輸出設備....等等,不過這些都是基本的,一般的 shell 都一定會支援的。
而為了讓 I/O 在使用上更有彈性,bash 支援了 pipeline(管線) 的功能,透過 pipeline 的方式,可以將多個程式結合起來,將 A 程式的 output 當作是 B 程式的 input,如此一來,就可以藉由此方式來完成更複雜的 I/O 工作了! 例:將 mail 檔案中的內容直接透過 lp 指令輸出到印表機上,而不是顯示在螢幕上。
pipeline 的支援,讓許多複雜的 I/O 工作變得容易完成,加上之後會介紹的 filtering 的功能(Linux 中有許多用在 filtering 的指令,例如:cat、grep、sort、cut、sed、tr....等等),便可以撰寫 shell script 來自動完成許多日常工作。
2、I/O Redirection
redirection 的功能可用來取代原本的 standard input 以及 standard output,分別以符號「<」代表 input,符號「>」代表 output,以下用個範例來說明:
shell> cat < file1 > file2上述指令會將 file1 的內容複製一份變成 file2,效果等同一下的指令:
shell> cp file1 file2瞭解了嗎? 在 bash shell 中,I/O 是可以做很多不同變化的。
3、Pipeline
在 standard I/O 中就有提到 pipeline 啦! 它的作用就是將某支程式所產生出來的 output 丟給另一支程式作為 input,所使用的符號為「|」,透過此符號將兩個以上不同的指令連結起來,讓前面指令的 output 成為下一個指令的 input。
以下舉個簡單例子:
shell> ls -al /home | more此指令會將 /home 目錄中的子目錄以及檔案通通列出來,包含隱藏檔,但是若內容很多,超過畫面一頁可以顯示的範圍,就透過 pipeline,將輸出交給 more 指令來做分頁瀏覽的效果,甚至可以交由 lp 指令直接從印表機輸出。
不過當然實際情況不會這麼簡單,在舉個例子,以儲存使用者帳號資訊的檔案 /etc/passwd 為例,每個使用者的帳號都會一行一行的存於此檔案中,格式如下:
man:x:6:12:man:/var/cache/man:/bin/sh每行中都包含著非常多的資訊,並且以冒號(:)作為間隔,至於這些資訊代表什麼意思,這邊不多做探討,假設我們只需要使用者帳號的部分,如果管理者希望將使用者帳號以字母的順序作排序後,並交由印表機列印出來,則可透過以下指令來完成:
shell> cut -d: -f1 < /etc/passwd | sort | lp看見了嗎? 在指令中把 redirection 跟 pipeline 的功能一起用上了! 如此一來達成我們想要的效果。當然,更複雜的指令也是可以完成,只是這就必須要透過大家的巧思了。
# 以下指令跟上面的相同
shell> cut -d: -f1 /etc/passwd | sort | lp
工作管理
由於 Unix-Like 系統強大的工作管理功能,不但讓使用者可以下指令同時做多個工作,也可以讓多個不同使用者同時登入,每個使用者有不同的 login session,可說是真正的 Multi-User 的操作環境。
在下指令進行某工作時,一般正常情況下,必須等到工作處理結束,才可以下另一個指令,但若是工作要處理很久的(例如:大型檔案的搬移),那可就要等半天囉! 但若不想這樣等,可以在指令的最後加上符號「&」,如此一來,工作就會移至背景去執行,馬上就可以下達下一個指令來處理另外一個工作了!
而透過加入符號「&」的指令所處理的工作,會產生一個 process number,供使用者隨時檢視之用,還可以使用 renice 的指令調整工作的處理優先權;此外,若要瞭解目前移至背景處理的工作的狀況,可用指令 jobs 來檢視。
不過需要注意的是,一般的 I/O 工作並不適合移到背景去執行,原因如下:
- 因為假如被移到背景的 I/O 工作需要使用者的 input,此時整個工作就會 stop,直到使用者將工作刪除,或是移回前景(foreground)來處理才會繼續。
- 假設被移至背景處理的 I/O 工作有任何資料要輸出時,一樣會出現在使用者的螢幕上,這樣一來,就會跟使用者正在處理的工作所產生的訊息混合輸出,造成螢幕訊息很混亂。不過這當然這也不是沒有解決方法,只要利用 redirection 的方式將輸出訊息轉到檔案或是 /dev/null 中,就可以解決此問題了!
特殊字元及引號
Unix-Like 系統提供了強大的功能,當然也需要有許多不同的特殊符號來搭配使用,例如「<」以及「>」使用來處理 I/O redirection,「&」則是將工作移至背景處理....等等,以下介紹各種不同特殊字元及引號的用法:
字元 | 功能說明 |
~ | home directory |
` | command substitution |
# | comment |
$ | variable expression |
& | background job |
* | string wildcard |
( | start subshell |
) | end subshell |
\ | quote next character |
| | pipe |
[ | start character-set wildcard |
] | end character-set wildcard |
{ | start command block |
} | end command block |
; | shell command separator |
' | strong quote |
<"> | weak quote |
< | input redirect |
> | output redirect |
/ | pathname directory separator |
? | single-character wildcard |
! | pipeline logical NOT |
1、引號與跳脫字元的使用
當使用者要在螢幕上單純顯示上述這些符號,為了讓 shell 不會誤判為特殊用途,必須搭配引號以及跳脫字元使用,假設我們要在螢幕上輸出「2 * 3 > 5 is a valid inquality」這一行訊息,其中包含了「*」及「>」兩個特殊字元,以下用幾個例子說明:
# 無法顯示正確訊息,反而會有其他非預期的訊息輸出至名稱為「5」的檔案中假設要顯示的訊息中,有引號呢? 如果這次訊息換成「"2 * 3 > 5" is a valid inquality」,這就一定非得要跳脫字元的協助不可了,可用以下指令來完成此需求:
shell> echo 2 * 3 > 5 is a valid inquality
# 正確顯示
shell> echo '2 * 3 > 5 is a valid inquality'
# 正確顯示
shell> '2 * 3 > 5' is a valid inquality
# 正確顯示
shell> echo 2 \* 3 \> 5 is a valid inquality
shell> echo \"2 \* 3 \> 5\" is a valid inquality
2、指令過長的處理方式
當使用者下的指令很長時,應該要怎麼處理呢? 這時候可以使用反斜線(\),也就是要使用跳脫字元所用的反斜線,shell 會認為指令尚未結束,讓使用者在下一行繼續輸入。
3、控制鍵
控制鍵可以在許多情況下可能會用到,例如:不小心下錯指令,要趕快停止時,按 Ctrl+C 停止指令的執行;或是想要暫停目前的工作,可按 Ctrl+Z.....等等,善用這些熱鍵,可讓工作更為順利,以下介紹常用的控制鍵:
控制鍵 | 功能說明 |
Ctrl + C | 終止目前執行中的命令 |
Ctrl + D | 結束輸入 |
Ctrl + \ | 終止目前執行中的命令(假設 Ctrl+C 沒有效用的話) |
Ctrl + S | 停止螢幕輸出訊息 |
Ctrl + Q | 重新輸出訊息至螢幕 |
Del or Ctrl + ? | 清除最後一個字元 |
Ctrl + U | 清除目前命令列中的指令 |
Ctrl + Z | 暫停目前的工作 |
參考資料:
沒有留言:
張貼留言