⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 1894.html

📁 著名的linux英雄站点的文档打包
💻 HTML
📖 第 1 页 / 共 5 页
字号:

前面我們提到的那些 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 中


或許,你能舉出更多的方案呢.... ^_^

5) var=value?export 前後差在哪? 

這次讓我們暫時丟開 command line ,先來了解一下 bash 變量(variable)吧... 

所謂的變量,就是就是利用一個特定的"名稱"(name)來存取一段可以變化的"值"(value)。 

*設定(set)* 
在 bash 中,你可以用 "=" 來設定或重新定義變量的內容: 
name=value 
在設定變量的時侯,得遵守如下規則: 
* 等號左右兩邊不能使用區隔符號(IFS),也應避免使用 shell 的保留字元(meta charactor)。 
* 變量名稱不能使用 $ 符號。 
* 變量名稱的第一個字母不能是數字(number)。 
* 變量名稱長度不可超過 256 個字母。 
* 變量名稱及變量值之大小寫是有區別的(case sensitive)。 

如下是一些變量設定時常見的錯誤: 
A= B :不能有 IFS 
1A=B :不能以數字開頭 
$A=B :名稱不能有 $ 
a=B :這跟 a=b 是不同的 
如下則是可以接受的設定: 
A=" B" :IFS 被關閉了 (請參考前面的 quoting 章節) 
A1=B :並非以數字開頭 
A=$B :$ 可用在變量值內 
This_Is_A_Long_Name=b :可用 _ 連接較長的名稱或值,且大小寫有別。 

*變量替換(substitution)* 
Shell 之所以強大,其中的一個因素是它可以在命令行中對變量作替換(substitution)處理。 
在命令行中使用者可以使用 $ 符號加上變量名稱(除了在用 = 號定義變量名稱之外), 
將變量值給替換出來,然後再重新組建命令行。 
比方: 
代码:
   $ A=ls 
   $ B=la 
   $ C=/tmp 
   $ $A -$B $C

(注意:以上命令行的第一個 $ 是 shell prompt ,並不在命令行之內。) 
必需強調的是,我們所提的變量替換,只發生在 command line 上面。(是的,讓我們再回到 command line 吧﹗) 
仔細分析最後那行 command line ,不難發現在被執行之前(在輸入 CR 字符之前), 
$ 符號會對每一個變量作替換處理(將變量值替換出來再重組命令行),最後會得出如下命令行: 
代码:
   ls -la /tmp

還記得第二章我請大家"務必理解"的那兩句嗎?若你忘了,那我這裡再重貼一遍: 
引用:
若從技術細節來看,shell 會依據 IFS(Internal Field Seperator) 將 command line 所輸入的文字給拆解為"字段"(word)。 
然後再針對特殊字符(meta)先作處理,最後再重組整行 command line 。 

這裡的 $ 就是 command line 中最經典的 meta 之一了,就是作變量替換的﹗ 
在日常的 shell 操作中,我們常會使用 echo 命令來查看特定變量的值,例如: 
代码:
   $ echo $A -$B $C

我們已學過, echo 命令只單純將其 argument 送至"標準輸出"(STDOUT,通常是我們的熒幕)。 
所以上面的命令會在熒幕上得到如下結果: 
代码:
   ls -la /tmp

這是由於 echo 命令在執行時,會先將 $A(ls)、$B(la)、跟 $C(/tmp) 給替換出來的結果。 

利用 shell 對變量的替換處理能力,我們在設定變量時就更為靈活了: 
A=B 
B=$A 
這樣,B 的變量值就可繼承 A 變量"當時"的變量值了。 
不過,不要以"數學羅輯"來套用變量的設定,比方說: 
A=B 
B=C 
這樣並不會讓 A 的變量值變成 C 。再如: 
A=B 
B=$A 
A=C 
同樣也不會讓 B 的值換成 C 。 
上面是單純定義了兩個不同名稱的變量:A 與 B ,它們的值分別是 B 與 C 。 
若變量被重復定義的話,則原有舊值將被新值所取代。(這不正是"可變的量"嗎? ^_^) 
當我們在設定變量的時侯,請記著這點: 
* 用一個名稱儲存一個數值 
僅此而已。 

此外,我們也可利用命令行的變量替換能力來"擴充"(append)變量值: 
A=B:C:D 
A=$A:E 
這樣,第一行我們設定 A 的值為 "B:C:D",然後,第二行再將值擴充為 "A:B:C:E" 。 
上面的擴充範例,我們使用區隔符號( : )來達到擴充目的, 
要是沒有區隔符號的話,如下是有問題的: 
A=BCD 
A=$AE 
因為第二次是將 A 的值繼承 $AE 的提換結果,而非 $A 再加 E ﹗ 
要解決此問題,我們可用更嚴謹的替換處理: 
A=BCD 
A=${A}E 
上例中,我們使用 {} 將變量名稱的範圍給明確定義出來, 
如此一來,我們就可以將 A 的變量值從 BCD 給擴充為 BCDE 。 

(提示:關於 ${name} 事實上還可做到更多的變量處理能力,這些均屬於比較進階的變量處理, 
現階段暫時不介紹了,請大家自行參考資料。如 CU 的貼子: 

<a href="javascript:if(confirm('http://www.chinaunix.net/forum/viewtopic.php?t=201843  \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address.  \n\nDo you want to open it from the server?'))window.location='http://www.chinaunix.net/forum/viewtopic.php?t=201843'" tppabs="http://www.chinaunix.net/forum/viewtopic.php?t=201843" target="_blank">http://www.chinaunix.net/forum/viewtopic.php?t=201843</a> 
) 

* export * 

嚴格來說,我們在當前 shell 中所定義的變量,均屬於"本地變量"(local variable), 
只有經過 export 命令的"輸出"處理,才能成為環境變量(environment variable): 
代码:
   $ A=B 
   $ export A

或: 
代码:
   $ export A=B

經過 export 輸出處理之後,變量 A 就能成為一個環境變量供其後的命令使用。 
在使用 export 的時侯,請別忘記 shell 在命令行對變量的"替換"(substitution)處理, 
比方說: 
代码:
   $ A=B 
   $ B=C 
   $ export $A

上面的命令並未將 A 輸出為環境變量,而是將 B 作輸出, 
這是因為在這個命令行中,$A 會首先被提換出 B 然後再"塞回"作 export 的參數。 

要理解這個 export ,事實上需要從 process 的角度來理解才能透徹。 
我將於下一章為大家說明 process 的觀念,敬請留意。 

*取消變量* 

要取消一個變量,在 bash 中可使用 unset 命令來處理: 
代码:
   unset A

與 export 一樣,unset 命令行也同樣會作變量替換(這其實就是 shell 的功能之一), 
因此: 
代码:
   $ A=B 
   $ B=C 
   $ unset $A

事實上所取消的變量是 B 而不是 A 。 

此外,變量一旦經過 unset 取消之後,其結果是將整個變量拿掉,而不僅是取消其變量值。 
如下兩行其實是很不一樣的: 
代码:
   $ A= 
   $ unset A

第一行只是將變量 A 設定為"空值"(null value),但第二行則讓變量 A 不在存在。 
雖然用眼睛來看,這兩種變量狀態在如下命令結果中都是一樣的: 
代码:
   $ A= 
   $ echo $A 

   $ unset A 
   $ echo $A 
   

請學員務必能識別 null value 與 unset 的本質區別,這在一些進階的變量處理上是很嚴格的。 
比方說: 
代码:
   $ str=      # 設為 null 
   $ var=${str=expr}   # 定義 var 
   $ echo $var 
    
   $ echo $str 
    
   $ unset str   # 取消 
   $ var=${str=expr}   # 定義 var 
   $ echo $var 
   expr 
   $ echo $str 
   expr

聰明的讀者(yes, you!),稍加思考的話, 
應該不難發現為何同樣的 var=${str=expr} 在 null 與 unset 之下的不同吧? 
若你看不出來,那可能是如下原因之一: 
a. 你太笨了 
b. 不了解 var=${str=expr} 這個進階處理 
c. 對本篇說明還沒來得及消化吸收 
e. 我講得不好 
不知,你選哪個呢?.... ^_^

6) exec 跟 source 差在哪? 

這次先讓我們從 CU Shell 版的一個實例貼子來談起吧: 
( <a href="javascript:if(confirm('http://www.chinaunix.net/forum/viewtopic.php?t=194191  \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address.  \n\nDo you want to open it from the server?'))window.location='http://www.chinaunix.net/forum/viewtopic.php?t=194191'" tppabs="http://www.chinaunix.net/forum/viewtopic.php?t=194191" target="_blank">http://www.chinaunix.net/forum/viewtopic.php?t=194191</a> ) 

例中的提問是: 
引用:

cd /etc/aa/bb/cc可以執行 
但是把這條命令寫入shell時shell不執行! 
這是什么原因呀! 


我當時如何回答暫時別去深究,先讓我們了解一下行程(process)的觀念好了。 
首先,我們所執行的任何程式,都是由父行程(parent process)所產生出來的一個子行程(child process), 
子行程在結束後,將返回到父行程去。此一現像在 Linux 系統中被稱為 fork 。 
(為何要程為 fork 呢?嗯,畫一下圖或許比較好理解... ^_^ ) 
當子行程被產生的時候,將會從父行程那裡獲得一定的資源分配、及(更重要的是)繼承父行程的環境﹗ 
讓我們回到上一章所談到的"環境變量"吧: 
* 所謂環境變量其實就是那些會傳給子行程的變量。 
簡單而言,"遺傳性"就是區分本地變量與環境變量的決定性指標。 
然而,從遺傳的角度來看,我們也不難發現環境變量的另一個重要特徵: 
* 環境變量只能從父行程到子行程單向繼承。換句話說:在子行程中的環境如何變更,均不會影響父行程的環境。 

接下來,再讓我們了解一下命令腳本(shell script)的概念。 
所謂的 shell script 講起來很簡單,就是將你平時在 shell prompt 後所輸入的多行 command line 依序寫入一個文件去而已。 
其中再加上一些條件判斷、互動界面、參數運用、函數調用、等等技巧,得以讓 script 更加"聰明"的執行, 
但若撇開這些技巧不談,我們真的可以簡單的看成 script 只不過依次執行預先寫好的命令行而已。 

再結合以上兩個概念(process + script),那應該就不難理解如下這句話的意思了: 
* 正常來說,當我們執行一個 shell script 時,其實是先產生一個 sub-shell 的子行程,然後 sub-shell 再去產生命令行的子行程。 
然則,那讓我們回到本章開始時所提到的例子再從新思考: 
引用:

cd /etc/aa/bb/cc可以執行 
但是把這條命令寫入shell時shell不執行! 
這是什么原因呀! 


我當時的答案是這樣的: 
引用:

因為,一般我們跑的 shell script 是用 subshell 去執行的。 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -