command line的每一个charactor,分为如下两种:
*literal:也就是普通纯文字,对shell来说没特殊功能。
*meta:对shell来说,具有特定功能的保留字元。
command中的meta:
IFS:由<space>或<tab>或 <enter>三者之一组成(常用space)
CR:由<enter>产生
=:设定变量
$:作变量或运算替换(不要跟shell prompt搞混了)
>:重定向stdout
<:重定向stdin
|:命令管道
&:重定向file descriptor,或将命令至于后台执行
():将其内的 命令至于nested subshell执行,或用于运算或命令替换
{}:将其内的命令至于non-named function 中执行,或用在变量替换的界定范围
;:在前一个命令结束是,而忽略其返回值,继续执行下一个命令
&&:在前一个命令结束是,如返回值为true,继续执行下一个命令
||:在前一个命令结束时,如返回值为false,继续执行下一个命令
!:执行history列表中的命令
在bash中,常用的quoting有如下三种方法:
*hard quote:''(单引号),凡在hard quote中的所有meta均被关闭
*soft quote:""(双引号),在soft quote中的大部分meta都会被关闭,但有些则保留(如$、\)。
*escape:\(反斜线),只有紧接在escape(跳脱字符)之后的单一meta才被关闭
例:
$ A="B
> C
> "
$ echo $A
B C
注:由于echo $A时的变量没至于soft quote中,因此当变量替换完成后并作命令行重组是,<enter>会被解释为IFS,而不是解释为New Line字符
$ A=B\
> C\
>
$ echo $A
BC
注:由于<enter>键本身在shell meta中的特殊性,在\跳脱后面,仅仅取消其CR功能,而不会保留其IFS功能
*区分出shell meta与command meta
前面提到的那些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 中