1.從使用者的角度來說,使用者也沒辦法直接操作 kernel , 而是透過 kernel 的"外殼"程序,也就是所謂的 shell ,來與 kernel 溝通。
每次當我們完成系統登入(log in), 我們就取得一個互動模式的 shell , 也稱爲 login she
或 primary shell。
若從行程(process)角度來說,我們在 shell 所下達的命令,均是 shell 所產生的子行程。
這現像,我們暫可稱之爲 fork 。
如果是執行腳本(shell script)的話,腳本中的命令則是由另外一個非互動模式的子 shell
(sub shell)來執行的。 也就是 primary shell 產生 sub shell 的行程,sub shell 再產生 script 中所有命令的行程。
2.這裏,我們必須知道:kernel 與 shell 是不同的兩套軟件,而且都是可以被替換的
* 不同的操作系統使用不同的 kernel ,
* 而在同一個 kernel 之上,也可使用不同的 shell 。
在 linux 的預設系統中,通常都可以找到好幾種不同的 shell ,且通常會被列於如
裏:
/etc/shells
不同的 shell 有着不同的功能,且也彼此各異、或說"大同小異"。
常見的 shell 主要分爲兩大主流:
sh:
burne shell (sh)
burne again shell (bash)
csh:
c shell (csh)
tc shell (tcsh)
korn shell (ksh)
3. shell prompt(PS1) 與 Carriage Return(CR) 的關係?
當你成功登錄進一個文字界面之後,大部份情形下, 你會在熒幕上看到一個不斷閃爍的方塊或底線(視不同版本而別), 我們稱之爲*遊標*(coursor)。
假如你剛完成登錄還沒輸入任何按鍵之前,你所看到的遊標所在位置的同一行的左邊部份。我們稱之爲*提示符號*(prompt)。
$:給一般使用者帳號使用
#:給 root (管理員)帳號使用
命令行讀進 CR(Carriage Return,由 Enter 鍵產生)
所謂的命令行,就是在 shell prompt 與 CR 字符之間所輸入的文字。
4.不同的命令可接受的命令行格式或有不同, 一般情況下, 一個標準的命令行格式爲如下所列:
command-name options argument
若從技術細節來看, shell 會依據 IFS(Internal Field Seperator) 將 command line 所
輸入的文字給拆解爲"字段"(word)。
然後再針對特殊字符(meta)先作處理,最後再重組整行 command line 。
其中的 IFS 是 shell 預設使用的字段分隔符,可以由一個及多個如下按鍵組成:
* 空格鍵(White Space)
* 表格鍵(Tab)
* 回車鍵(Enter)
系統可接受的命令名稱(command-name)可以從如下途徑獲得:
* 明確路徑所指定的外部命令
* 命令別名(alias)
* 自定功能(function)
* shell 內建命令(built-in)
* $PATH 之下的外部命令
每一個命令行均必需含用命令名稱,這是不能缺少的。
5.關於echo
$ echo -n 不換行輸出
事實上,echo 除了 -n options 之外,常用選項還有:
-e :啓用反斜線控制字符的轉換(參考下表)
-E:關閉反斜線控制字符的轉換(預設如此)
-n :取消行末之換行符號(與 -e 選項下的 \c 字符同意)
關於 echo 命令所支持的反斜線控制字符如下表:
\a:ALERT / BELL (從系統喇叭送出鈴聲)
b:BACKSPACE ,也就是向左刪除鍵
\c:取消行末之換行符號
\E:ESCAPE,跳脫鍵
\f:FORMFEED,換頁字符
\n:NEWLINE,換行字符
\r:RETURN,回車鍵
\t:TAB,表格跳位鍵
\v:VERTICAL TAB,垂直表格跳位鍵
\n:ASCII 八進位編碼(以 x 開首爲十六進制)
\\:反斜線本身
6. 關於command
command line 的每一個 charactor ,分爲如下兩種
* literal:也就是普通純文字,對 shell 來說沒特殊功能。
* meta:對 shell 來說,具有特定功能的特殊保留字符。
而 CR 則是用來結束 command line 用的,這也是爲何我們敲 <enter> 命令就會跑的原
除了 IFS 與 CR ,常用的 meta 還有:
= : 設定變量。
$ : 作變量或運算替換(請不要與 shell prompt 搞混了)。
> :重導向 stdout。
< :重導向 stdin。
|:命令管線。
& :重導向 file descriptor ,或將命令置於背境執行。
( ):將其內的命令置於 nested subshell 執行,或用於運算或命令替換。
{ }:將其內的命令置於 non-named function 中執行,或用在變量替換的界定範圍。
; :在前一個命令結束時,而忽略其返回值,繼續執行下一個命令。
&& :在前一個命令結束時,若返回值爲 true,繼續執行下一個命令。
|| :在前一個命令結束時,若返回值爲 false,繼續執行下一個命令。
!:執行 history 列表中的命令
....
7.quoting
在 bash 中,常用的 quoting 有如下三種方法:
* hard quote:' ' (單引號),凡在 hard quote 中的所有 meta 均被關閉。
* soft quote: " " (雙引號),在 soft quoe 中大部份 meta 都會被關閉,但某些則保留(如
$ )。(注二)
* escape : \ (反斜線),只有緊接在 escape (跳脫字符)之後的單一 meta 才被關閉。
( 注二:在 soft quote 中被豁免的具體 meta 清單,我不完全知道,
有待大家補充,或透過實作來發現及理解。 )
代碼:
$ A=B C # 空格鍵未被關掉,作爲 IFS 處理。
$ C: command not found.
$ echo $A
$ A="B C" # 空格鍵已被關掉,僅作爲空格鍵處理。
$ echo $A
B
C
$ A="B
> C
> "
$ echo $A
B C
$ A=B\
> C\
>
$ echo $A
BC
$ A=B\ C
$ echo "$A"
B C
$ echo '$A'
$A
$ A=B\ C
$ echo '"$A"' # 最外面的是單引號
"$A"
$ echo "'$A'" # 最外面的是雙引號
'B C'
(提示:單引號及雙引號,在 quoting 中均被關?#93;了。)
8.前面我們提到的那些 meta ,都是在 command line 中有特殊用途的,
比方說 { } 是將其內一系列 command line 置於不具名的函式中執行(可簡單視爲
command block ),
但是,awk 卻需要用 { } 來區分出 awk 的命令區段(BEGIN, MAIN, END)。
若你在 command line 中如此輸入:
$ awk {print $0} 1.txt
由於 { } 在 shell 中並沒關閉,那 shell 就將 {print $0} 視爲 command block ,
但同時又沒有" ; "符號作命令區隔,因此就出現 awk 的語法錯誤結果。
要解決之,可用 hard quote :
$ awk '{print $0}' 1.txt
上面的 hard quote 應好理解,就是將原本的 {、<space>、$(注三)、} 這幾個 shell meta 關閉, 避免掉在 shell 中遭到處理,而完整的成爲 awk 參數中的 command meta 。
( 注三:而其中的 $0 是 awk 內建的 field number ,而非 awk 的變量,
awk 自身的變量無需使用 $ 。)
要是理解了 hard quote 的功能,再來理解 soft quote 與 escape 就不難:
awk "{print \$0}" 1.txt
awk \{print\ \$0\} 1.txt
然而,若你要改變 awk 的 $0 的 0 值是從另一個 shell 變量讀進呢?
比方說:已有變量 $A 的值是 0 ,那如何在 command line 中解決 awk 的 $$A 呢? 你可以很直接否定掉 hard quoe 的方案:
$ awk '{print $$A}' 1.txt
那是因爲 $A 的 $ 在 hard quote 中是不能替換變量的。
我想,應該可以解釋爲何我們可以使用如下操作了吧:
代碼:
A=0
awk "{print \$$A}" 1.txt
awk \{print\ \$$A\} 1.txt
awk '{print $'$A'}' 1.txt
awk '{print $'"$A"'}' 1.txt # 注:"$A" 包在 soft quote 中