<?xml version="1.0" encoding="gb2312"?>
	<rss version="2.0">
		<channel>
		<title><![CDATA[陶金BLOG]]></title>
		<description><![CDATA[]]></description>
		<link>http://www.cublog.cn/u/250/</link>
		<language>zh-cn</language>
		<generator>www.cublog.cn</generator>
		<copyright>Copyright 2010 ChinaUnix.Net All Rights Reserved</copyright>
		<pubDate>Mon, 06 Sep 2010 03:14:31 GMT</pubDate>
	
		<item>
			<title><![CDATA[金蝶K3存货核算难点剖析-存货暂估]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=1840039]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Mon, 23 Feb 2009 08:54:30 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[  ]]></description>
		</item>	
			<item>
			<title><![CDATA[RMAN 备份文档]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=1090974]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Thu, 24 Jul 2008 09:34:06 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV>
<DIV class=storytext>我們在RMAN中可以通過CONFIGURE這個Command來固定一些在以前版本中要手工輸入的信息，如備份文件的存放路徑及文件名，備份文件的大小，備份策略。控制文件的備份等。下面列出在RMAN中常見的可以用于設定的信息（以及一些實例）<BR>
<P><STRONG>------------------------------------------------------------<BR>--configure (配置RMAN的default設置)<BR>------------------------------------<BR>--1 顯示當前的configure<BR></STRONG>RMAN&gt; show all;</P>
<P>RMAN configuration parameters are:<BR>C……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[RMAN备份语法]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=1070145]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Mon, 30 Jun 2008 13:39:26 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV>最近一直希望找一个RMAN语法手册去查查，终于在ORACLE 文档找到了，发出来共享一下，更多ORACLE资料可以到<A href="http://blog.chinaunix.com/u/250">http://blog.chinaunix.com/u/250</A>下载<BR>archivelogRecordSpecifier<BR>This subclause specifies a range of archived redo logs.<BR>ARCHIVELOG<BR>{ ALL<BR>| LIKE 'string_pattern'<BR>| archlogRange [LIKE 'string_pattern' [THREAD [=] integer]]<BR>}<BR>{ { { UNTIL TIME | FROM TIME } [=] 'date_string'<BR>| { TIME BETWEEN 'date_string' AND<BR>| FROM TIME [=]……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[Shell 编程13问(太经典了)]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=293093]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Mon, 07 May 2007 02:10:54 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV>1) 為何叫做 shell ？ </DIV>
<DIV>在介紹 shell 是甚麼東西之前，不妨讓我們重新檢視使用者與電腦系統的關係：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 圖(FIXME)</DIV>
<DIV>我們知道電腦的運作不能離開硬體，但使用者卻無法直接對硬體作驅動，<BR>硬體的驅動只能透過一個稱為"作業系統(Operating System)"的軟體來控管，<BR>事實上，我們每天所談的 linux ，嚴格來說只是一個作業系統，我們稱之為"核心(kernel)"。<BR>然而，從使用者的角度來說，使用者也沒辦法直接操作 kernel ，<BR>而是透過 kernel 的"外殼"程式，也就是所謂的 shell ，來與 kernel 溝通。<BR>這也正是 kernel 跟 shell 的形像命名關係。如圖：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 圖(FIXME)</DIV>
<DIV>從技術角度來說，shell 是一個使用者與系統的互動界面(interface)，<BR>主要是讓使用者透過命令行(command line)來使用系統以完成工作。<BR>因此，shell 的最簡單的定義就是---命令解譯器(Command Interpreter)：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 將使用者的命令翻譯給核心處理，<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 同時，將核心處理結果翻譯給使用者。</DIV>
<DIV>每次當我們完成系統登入(log in)，我們就取得一個互動模式的 shell ，也稱為 login shell 或 primary shell。<BR>若從行程(process)角度來說，我們在 shell 所下達的命令，均是 shell 所產生的子行程。這現像，我們暫可稱之為 fork 。<BR>如果是執行腳本(shell script)的話，腳本中的命令則是由另外一個非互動模式的子 shell (sub shell)來執行的。<BR>也就是 primary shell 產生 sub shell 的行程，sub shell 再產生 script 中所有命令的行程。<BR>(關於行程，我們日後有機會再補充。)</DIV>
<DIV>這裡，我們必須知道：kernel 與 shell 是不同的兩套軟體，而且都是可以被替換的：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 不同的作業系統使用不同的 kernel ，<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 而在同一個 kernel 之上，也可使用不同的 shell 。<BR>在 linux 的預設系統中，通常都可以找到好幾種不同的 shell ，且通常會被列於如下檔案裡：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /etc/shells<BR>不同的 shell 有著不同的功能，且也彼此各異、或說"大同小異"。<BR>常見的 shell 主要分為兩大主流：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; burne shell (sh)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; burne again shell (bash)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; csh：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c shell (csh)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tc shell (tcsh)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; korn shell (ksh)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (FIXME)</DIV>
<DIV>大部份的 Linux 系統的預設 shell 都是 bash ，其原因大致如下兩點：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 自由軟體<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 功能強大<BR>bash 是 gnu project 最成功的產品之一，自推出以來深受廣大 Unix 用戶喜愛，<BR>且也逐漸成為不少組織的系統標準。 </DIV>
<DIV>关于{}和()<BR>1.{} 的用法<BR>确认你有一个叫file和一个叫file1的变量。能够使用以下的语句给它们赋值：<BR>$ file=this<BR>$ file1=that<BR>$echo $fileand$file1 寻找变量fileand,file1<BR>sh: fileand: parameter not set <BR>$ echo ${file} and $file1 寻找变量file,file1<BR>thisandthat<BR>花括号被用来区分变量名和周围的文本<BR>2.()的用法<BR>命令替代 <BR>语法：<BR>$(command)<BR>例子：<BR>$pwd<BR>/home/user2<BR>$ curdir=$(pwd)<BR>$ echo $curdir<BR>/home/user2<BR>$ cd /tmp<BR>$ pwd<BR>$ cd $curdir<BR>$ pwd<BR>/home/user2<BR>命令替代用来替代一个命令和命令行输出。命令替代的标准语法，也是POSIX鼓励的一种语法是：$(command).<BR>命令替代让你捕获一个命令的输出，用它作为另一个命令的参数，或是赋值给一个变量。象在变量替代中一样，命令替代的执行是在命令行开始之前完成的。当命令行输出包含回车换行，它们会被空格代替。<BR>同变量替代相似，命令替代使用一个美元符号之后的用括号包围的一个命令。<BR>所有有效的shell脚本都可以加入命令替代。Shell 扫描每行脚本，执行它发现的开始于一个开括号，结束与于一个闭括号的命令。<BR>命令替代的另外一种格式是用反引号来环绕一个命令象：<BR>`command`<BR>它和$(command) 是等价的，并且这是Bourne Shell认证的唯一的形式。`command`形式可以用在POSIX的脚本中和Bourne Shell的脚本中。<BR>命令替代通常是在将一个命令的输出赋给一个变量或以后的处理时使用。通常pwd命令将它的输出送到你的屏幕。当你执行以下的赋值语句：<BR>$ curdir=$(pwd) 或 $ curdir=`pwd`<BR>pwd 的输出被赋给变量 curdir。</DIV>
<DIV><BR>2) shell prompt(PS1) 與 Carriage Return(CR) 的關係？ </DIV>
<DIV>當你成功登錄進一個文字界面之後，大部份情形下，<BR>你會在熒幕上看到一個不斷閃爍的方塊或底線(視不同版本而別)，<BR>我們稱之為*遊標*(coursor)。<BR>遊標的作用就是告訴你接下來你從鍵盤輸入的按鍵所插入的位置，<BR>且每輸如一鍵遊標便向右邊移動一個格子，若連續輸入太多的話，則自動接在下一行輸入。</DIV>
<DIV>假如你剛完成登錄還沒輸入任何按鍵之前，你所看到的遊標所在位置的同一行的左邊部份，<BR>我們稱之為*提示符號*(prompt)。<BR>提示符號的格式或因不同系統版本而各有不同，在 Linux 上，只需留意最接近遊標的一個可見的提示符號，通常是如下兩者之一：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $：給一般使用者帳號使用<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #：給 root (管理員)帳號使用</DIV>
<DIV>事實上，shell prompt 的意思很簡單：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 是 shell 告訴使用者：您現在可以輸入命令行了。<BR>我們可以說，使用者只有在得到 shell prompt 才能打命令行，<BR>而 cursor 是指示鍵盤在命令行所輸入的位置，使用者每輸入一個鍵，cursor 就往後移動一格，<BR>直到碰到命令行讀進 CR(Carriage Return，由 Enter 鍵產生)字符為止。<BR>CR 的意思也很簡單：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 是使用者告訴 shell：老兄你可以執行我的命令行了。<BR>嚴格來說：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 所謂的命令行，就是在 shell prompt 與 CR 字符之間所輸入的文字。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (思考：為何我們這裡堅持使用 CR 字符而不說 Enter 鍵呢？答案在後面的學習中揭曉。)</DIV>
<DIV>不同的命令可接受的命令行格式或有不同，一般情況下，一個標準的命令行格式為如下所列：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; command-name options argument</DIV>
<DIV>若從技術細節來看，shell 會依據 IFS(Internal Field Seperator) 將 command line 所輸入的文字給拆解為"字段"(word)。<BR>然後再針對特殊字符(meta)先作處理，最後再重組整行 command line 。<BR>(注意：請務必理解上兩句話的意思，我們日後的學習中會常回到這裡思考。)</DIV>
<DIV>其中的 IFS 是 shell 預設使用的欄位分隔符號，可以由一個及多個如下按鍵組成：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 空白鍵(White Space)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 表格鍵(Tab)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 回車鍵(Enter)</DIV>
<DIV>系統可接受的命令名稱(command-name)可以從如下途逕獲得：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 明確路逕所指定的外部命令<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 命令別名(alias)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 自定功能(function)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * shell 內建命令(built-in)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * $PATH 之下的外部命令<BR>每一個命令行均必需含用命令名稱，這是不能缺少的。 </DIV>
<DIV>3) 別人 echo、你也 echo ，是問 echo 知多少？</DIV>
<DIV>承接上一章所介紹的&nbsp; command line ，這裡我們用 echo 這個命令加以進一步說明。<BR>溫習---標準的 command line 包含三個部件：<BR>* command_name option argument </DIV>
<DIV>echo 是一個非常簡單、直接的 Linux 命令：<BR>* 將 argument 送出至標準輸出(STDOUT)，通常就是在監視器(monitor)上輸出。<BR>(註：stdout 我們日後有機會再解說，或可先參考如下討論：<BR><A href="http://www.chinaunix.net/forum/viewtopic.php?t=191375">http://www.chinaunix.net/forum/viewtopic.php?t=191375</A> )</DIV>
<DIV>為了更好理解，不如先讓我們先跑一下 echo 命令好了：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ echo</DIV>
<DIV>$<BR>你會發現只有一個空白行，然後又回到 shell prompt 上了。<BR>這是因為 echo 在預設上，在顯示完 argument 之後，還會送出一個換行符號(new-line charactor)。<BR>但是上面的 command 並沒任何的 argument ，那結果就只剩一個換行符號了...<BR>若你要取消這個換行符號，可利用 echo 的 -n option ：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ echo -n<BR>$<BR>不妨讓我們回到 command line 的概念上來討論上例的 echo 命令好了：<BR>* command line 只有 command_name(echo) 及 option(-n)，並沒有任何 argument 。<BR>要想看看 echo 的 argument ，那還不簡單﹗接下來，你可試試如下的輸入：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ echo first line<BR>first line<BR>$ echo -n first line<BR>first line $<BR>於上兩個 echo 命令中，你會發現 argument 的部份顯示在你的熒幕，而換行符號則視 -n option 的有無而別。<BR>很明顯的，第二個 echo 由於換行符號被取消了，接下來的 shell prompt 就接在輸出結果同一行了... ^_^</DIV>
<DIV>事實上，echo 除了 -n options 之外，常用選項還有：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -e ：啟用反斜線控制字符的轉換(參考下表)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -E：關閉反斜線控制字符的轉換(預設如此)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -n ：取消行末之換行符號(與 -e 選項下的 \c 字符同意)</DIV>
<DIV>關於 echo 命令所支援的反斜線控制字符如下表：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \a：ALERT / BELL (從系統喇叭送出鈴聲)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \b：BACKSPACE ，也就是向左刪除鍵<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \c：取消行末之換行符號<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \E：ESCAPE，跳脫鍵<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \f：FORMFEED，換頁字符<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n：NEWLINE，換行字符<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \r：RETURN，回車鍵<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \t：TAB，表格跳位鍵<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \v：VERTICAL TAB，垂直表格跳位鍵<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n：ASCII 八進位編碼(以 x 開首為十六進位)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \\：反斜線本身<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (表格資料來自 O'Reilly 出版社之 Learning the Bash Shell, 2nd Ed.)</DIV>
<DIV>或許，我們可以透過實例來了解 echo 的選項及控制字符：</DIV>
<DIV>例一：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ echo -e "a\tb\tc\nd\te\tf"<BR>a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<BR>d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f<BR>上例運用 \t 來區隔 abc 還有 def ，及用 \n 將 def 換至下一行。</DIV>
<DIV>例二：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ echo -e "\141\011\142\011\143\012\144\011\145\011\146"<BR>a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<BR>d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f<BR>與例一的結果一樣，只是使用 ASCII 八進位編碼。</DIV>
<DIV>例三：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ echo -e "\x61\x09\x62\x09\x63\x0a\x64\x09\x65\x09\x66"<BR>a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<BR>d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f<BR>與例二差不多，只是這次換用 ASCII 十六進位編碼。</DIV>
<DIV>例四：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ echo -ne "a\tb\tc\nd\te\bf\a"<BR>a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c<BR>d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f $<BR>因為 e 字母後面是刪除鍵(\b)，因此輸出結果就沒有 e 了。<BR>在結束時聽到一聲鈴嚮，那是 \a 的傑作﹗<BR>由於同時使用了 -n 選項，因此 shell prompt 緊接在第二行之後。<BR>若你不用 -n 的話，那你在 \a 後再加個 \c ，也是同樣的效果。</DIV>
<DIV>事實上，在日後的 shell 操作及 shell script 設計上，echo 命令是最常被使用的命令之一。<BR>比方說，用 echo 來檢查變量值：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ A=B<BR>$ echo $A<BR>B<BR>$ echo $?<BR>0<BR>(註：關於變量概念，我們留到下兩章才跟大家說明。)</DIV>
<DIV>好了，更多的關於 command line 的格式，以及 echo 命令的選項，<BR>就請您自行多加練習、運用了... </DIV>
<DIV><BR>4) " "(雙引號) 與 ' '(單引號)差在哪？ </DIV>
<DIV>還是回到我們的 command line 來吧...<BR>經過前面兩章的學習，應該很清楚當你在 shell prompt 後面敲打鍵盤、直到按下 Enter 的時候，<BR>你輸入的文字就是 command line 了，然後 shell 才會以行程的方式執行你所交給它的命令。<BR>但是，你又可知道：你在 command line 輸入的每一個文字，對 shell 來說，是有類別之分的呢？</DIV>
<DIV>簡單而言(我不敢說這是精確的定議，註一)，command line 的每一個 charactor ，分為如下兩種：<BR>* literal：也就是普通純文字，對 shell 來說沒特殊功能。<BR>* meta：對 shell 來說，具有特定功能的特殊保留字元。<BR>(註一：關於 bash shell 在處理 command line 時的順序說明，<BR>請參考 O'Reilly 出版社之 Learning the Bash Shell, 2nd Edition，第 177 - 180 頁的說明，<BR>尤其是 178 頁的流程圖 Figure 7-1 ... )</DIV>
<DIV>Literal 沒甚麼好談的，凡舉 abcd、123456 這些"文字"都是 literal ... (easy？)<BR>但 meta 卻常使我們困惑..... (confused?)<BR>事實上，前兩章我們在 command line 中已碰到兩個機乎每次都會碰到的 meta ：<BR>* IFS：由 &lt;space&gt; 或 &lt;tab&gt; 或 &lt;enter&gt; 三者之一組成(我們常用 space )。<BR>* CR：由 &lt;enter&gt; 產生。<BR>IFS 是用來拆解 command line 的每一個詞(word)用的，因為 shell command line 是按詞來處理的。<BR>而 CR 則是用來結束 command line 用的，這也是為何我們敲 &lt;enter&gt; 命令就會跑的原因。<BR>除了 IFS 與 CR ，常用的 meta 還有：<BR>= ：&nbsp; 設定變量。<BR>$ ：&nbsp; 作變量或運算替換(請不要與 shell prompt 搞混了)。<BR>&gt; ：重導向 stdout。<BR>&lt; ：重導向 stdin。<BR>|：命令管線。<BR>&amp; ：重導向 file descriptor ，或將命令置於背境執行。<BR>( )：將其內的命令置於 nested subshell 執行，或用於運算或命令替換。<BR>{ }：將其內的命令置於 non-named function 中執行，或用在變量替換的界定範圍。<BR>; ：在前一個命令結束時，而忽略其返回值，繼續執行下一個命令。<BR>&amp;&amp; ：在前一個命令結束時，若返回值為 true，繼續執行下一個命令。<BR>|| ：在前一個命令結束時，若返回值為 false，繼續執行下一個命令。<BR>!：執行 history 列表中的命令<BR>....</DIV>
<DIV>假如我們需要在 command line 中將這些保留字元的功能關閉的話，就需要 quoting 處理了。<BR>在 bash 中，常用的 quoting 有如下三種方法：<BR>* hard quote：' ' (單引號)，凡在 hard quote 中的所有 meta 均被關閉。<BR>* soft quote： " " (雙引號)，在 soft quoe 中大部份 meta 都會被關閉，但某些則保留(如 $ )。(註二)<BR>* escape ： \ (反斜線)，只有緊接在 escape (跳脫字符)之後的單一 meta 才被關閉。<BR>( 註二：在 soft quote 中被豁免的具體 meta 清單，我不完全知道，<BR>有待大家補充，或透過實作來發現及理解。 )</DIV>
<DIV>下面的例子將有助於我們對 quoting 的了解：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A=B C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 空白鍵未被關掉，作為 IFS 處理。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ C: command not found. <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $A<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A="B C"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 空白鍵已被關掉，僅作為空白鍵處理。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $A<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B C<BR>在第一次設定 A 變量時，由於空白鍵沒被關閉，command line 將被解讀為：<BR>* A=B 然後碰到&lt;IFS&gt;，再執行 C 命令<BR>在第二次設定&nbsp; A 變量時，由於空白鍵被置於 soft quote 中，因此被關閉，不再作為 IFS ：<BR>* A=B&lt;space&gt;C<BR>事實上，空白鍵無論在 soft quote 還是在 hard quote 中，均會被關閉。Enter 鍵亦然：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A='B<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; C<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; '<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo "$A"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C<BR>在上例中，由於 &lt;enter&gt; 被置於 hard quote 當中，因此不再作為 CR 字符來處理。<BR>這裡的 &lt;enter&gt; 單純只是一個斷行符號(new-line)而已，由於 command line 並沒得到 CR 字符，<BR>因此進入第二個 shell prompt (PS2，以 &gt; 符號表示)，command line 並不會結束，<BR>直到第三行，我們輸入的 &lt;enter&gt; 並不在&nbsp; hard quote 裡面，因此並沒被關閉，<BR>此時，command line 碰到 CR 字符，於是結束、交給 shell 來處理。</DIV>
<DIV>上例的 &lt;enter&gt; 要是被置於 soft quote 中的話， CR 也會同樣被關閉：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A="B<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; C<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; "<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $A<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B C<BR>然而，由於 echo $A 時的變量沒至於 soft quote 中，因此當變量替換完成後並作命令行重組時，&lt;enter&gt; 會被解釋為 IFS ，而不是解釋為 New Line 字符。</DIV>
<DIV>同樣的，用 escape 亦可關閉 CR 字符：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A=B\<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt; C\<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $A<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BC<BR>上例中，第一個 &lt;enter&gt; 跟第二個 &lt;enter&gt; 均被 escape 字符關閉了，因此也不作為 CR 來處理，<BR>但第三個 &lt;enter&gt; 由於沒被跳脫，因此作為 CR 結束 command line 。<BR>但由於 &lt;enter&gt; 鍵本身在 shell meta 中的特殊性，在 \ 跳脫後面，僅僅取消其 CR 功能，而不會保留其 IFS 功能。</DIV>
<DIV>您或許發現光是一個 &lt;enter&gt; 鍵所產生的字符就有可能是如下這些可能：<BR>CR<BR>IFS<BR>NL(New Line)<BR>FF(Form Feed)<BR>NULL<BR>...<BR>至於甚麼時候會解釋為甚麼字符，這個我就沒去深挖了，或是留給讀者諸君自行慢慢摸索了... ^_^</DIV>
<DIV>至於 soft quote 跟 hard quote 的不同，主要是對於某些 meta 的關閉與否，以 $ 來作說明：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A=B\ C<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo "$A"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B C<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo '$A'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $A<BR>在第一個 echo 命令行中，$ 被置於 soft quote 中，將不被關閉，因此繼續處理變量替換，<BR>因此 echo 將 A 的變量值輸出到熒幕，也就得到&nbsp; "B C" 的結果。<BR>在第二個 echo 命令行中，$ 被置於 hard quote 中，則被關閉，因此 $ 只是一個 $ 符號，<BR>並不會用來作變量替換處理，因此結果是 $ 符號後面接一個 A 字母：$A 。</DIV>
<DIV>--------------------------------------<BR>練習與思考：如下結果為何不同？</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A=B\ C<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo '"$A"'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 最外面的是單引號<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "$A"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo "'$A'"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 最外面的是雙引號<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'B C'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (提示：單引號及雙引號，在 quoting 中均被關?#93;了。)<BR>--------------------------------------</DIV>
<DIV>在 CU 的 shell 版裡，我發現有很多初學者的問題，都與 quoting 理解的有關。<BR>比方說，若我們在 awk 或 sed 的命令參數中調用之前設定的一些變量時，常會問及為何不能的問題。<BR>要解決這些問題，關鍵點就是：<BR>* 區分出 shell meta 與 command meta </DIV>
<DIV>前面我們提到的那些 meta ，都是在 command line 中有特殊用途的，<BR>比方說 { } 是將其內一系列 command line 置於不具名的函式中執行(可簡單視為 command block )，<BR>但是，awk 卻需要用 { } 來區分出 awk 的命令區段(BEGIN, MAIN, END)。<BR>若你在 command line 中如此輸入：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ awk {print $0} 1.txt<BR>由於&nbsp; { } 在 shell 中並沒關閉，那 shell 就將 {print $0} 視為 command block ，<BR>但同時又沒有" ; "符號作命令區隔，因此就出現 awk 的語法錯誤結果。</DIV>
<DIV>要解決之，可用 hard quote ：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ awk '{print $0}' 1.txt<BR>上面的 hard quote 應好理解，就是將原本的 {、&lt;space&gt;、$(註三)、} 這幾個 shell meta 關閉，<BR>避免掉在 shell 中遭到處理，而完整的成為 awk 參數中的 command meta 。<BR>( 註三：而其中的 $0 是 awk 內建的 field number ，而非&nbsp; awk 的變量，<BR>awk 自身的變量無需使用 $ 。)<BR>要是理解了 hard quote 的功能，再來理解 soft quote 與 escape 就不難：</DIV>
<DIV><BR>CODE:[Copy to clipboard]awk "{print \$0}" 1.txt<BR>awk \{print\ \$0\} 1.txt<BR>然而，若你要改變 awk 的 $0 的 0 值是從另一個 shell 變量讀進呢？<BR>比方說：已有變量 $A 的值是 0 ，那如何在 command line 中解決 awk 的 $$A 呢？<BR>你可以很直接否定掉 hard quoe 的方案：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ awk '{print $$A}' 1.txt<BR>那是因為 $A 的 $ 在 hard quote 中是不能替換變量的。</DIV>
<DIV>聰明的讀者(如你!)，經過本章學習，我想，應該可以解釋為何我們可以使用如下操作了吧：</DIV>
<DIV><BR>CODE:[Copy to clipboard]A=0<BR>awk "{print \$$A}" 1.txt<BR>awk \{print\ \$$A\} 1.txt<BR>awk '{print $'$A'}' 1.txt<BR>awk '{print $'"$A"'}' 1.txt&nbsp;&nbsp;&nbsp;&nbsp; # 注："$A" 包在 soft quote 中<BR>或許，你能舉出更多的方案呢....&nbsp; ^_^</DIV>
<DIV><BR>5) var=value？export 前後差在哪？</DIV>
<DIV>這次讓我們暫時丟開 command line ，先來了解一下 bash 變量(variable)吧...</DIV>
<DIV>所謂的變量，就是就是利用一個特定的"名稱"(name)來存取一段可以變化的"值"(value)。</DIV>
<DIV>*設定(set)*<BR>在 bash 中，你可以用 "=" 來設定或重新定義變量的內容：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name=value<BR>在設定變量的時侯，得遵守如下規則：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 等號左右兩邊不能使用區隔符號(IFS)，也應避免使用 shell 的保留字元(meta charactor)。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 變量名稱不能使用 $ 符號。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 變量名稱的第一個字母不能是數字(number)。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 變量名稱長度不可超過 256 個字母。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 變量名稱及變量值之大小寫是有區別的(case sensitive)。</DIV>
<DIV>如下是一些變量設定時常見的錯誤：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A= B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：不能有 IFS<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1A=B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：不能以數字開頭<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $A=B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：名稱不能有 $<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a=B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：這跟 a=b 是不同的<BR>如下則是可以接受的設定：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=" B"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：IFS 被關閉了 (請參考前面的 quoting 章節)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A1=B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：並非以數字開頭<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=$B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：$ 可用在變量值內<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This_Is_A_Long_Name=b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：可用 _ 連接較長的名稱或值，且大小寫有別。</DIV>
<DIV>*變量替換(substitution)*<BR>Shell 之所以強大，其中的一個因素是它可以在命令行中對變量作替換(substitution)處理。<BR>在命令行中使用者可以使用 $ 符號加上變量名稱(除了在用 = 號定義變量名稱之外)，<BR>將變量值給替換出來，然後再重新組建命令行。<BR>比方：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A=ls<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ B=la<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ C=/tmp<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ $A -$B $C<BR>(注意：以上命令行的第一個 $ 是 shell prompt ，並不在命令行之內。)<BR>必需強調的是，我們所提的變量替換，只發生在 command line 上面。(是的，讓我們再回到 command line 吧﹗)<BR>仔細分析最後那行 command line ，不難發現在被執行之前(在輸入 CR 字符之前)，<BR>$ 符號會對每一個變量作替換處理(將變量值替換出來再重組命令行)，最後會得出如下命令行：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ls -la /tmp<BR>還記得第二章我請大家"務必理解"的那兩句嗎？若你忘了，那我這裡再重貼一遍：</DIV>
<DIV><BR>QUOTE:<BR>若從技術細節來看，shell 會依據 IFS(Internal Field Seperator) 將 command line 所輸入的文字給拆解為"字段"(word)。 <BR>然後再針對特殊字符(meta)先作處理，最後再重組整行 command line 。 <BR>這裡的 $ 就是 command line 中最經典的 meta 之一了，就是作變量替換的﹗<BR>在日常的 shell 操作中，我們常會使用 echo 命令來查看特定變量的值，例如：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $A -$B $C<BR>我們已學過， echo 命令只單純將其 argument 送至"標準輸出"(STDOUT，通常是我們的熒幕)。 <BR>所以上面的命令會在熒幕上得到如下結果：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ls -la /tmp<BR>這是由於 echo 命令在執行時，會先將 $A(ls)、$B(la)、跟 $C(/tmp) 給替換出來的結果。</DIV>
<DIV>利用 shell 對變量的替換處理能力，我們在設定變量時就更為靈活了：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=B<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B=$A<BR>這樣，B 的變量值就可繼承 A 變量"當時"的變量值了。<BR>不過，不要以"數學羅輯"來套用變量的設定，比方說：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=B<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B=C<BR>這樣並不會讓 A 的變量值變成 C 。再如：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=B<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B=$A<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=C<BR>同樣也不會讓 B 的值換成 C 。<BR>上面是單純定義了兩個不同名稱的變量：A 與&nbsp; B ，它們的值分別是 B 與&nbsp; C 。<BR>若變量被重復定義的話，則原有舊值將被新值所取代。(這不正是"可變的量"嗎？&nbsp; ^_^)<BR>當我們在設定變量的時侯，請記著這點：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 用一個名稱儲存一個數值<BR>僅此而已。</DIV>
<DIV>此外，我們也可利用命令行的變量替換能力來"擴充"(append)變量值：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=B:C:D<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=$A:E<BR>這樣，第一行我們設定 A 的值為 "B:C:D"，然後，第二行再將值擴充為 "B:C:D:E" 。<BR>上面的擴充範例，我們使用區隔符號( : )來達到擴充目的，<BR>要是沒有區隔符號的話，如下是有問題的：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=BCD<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=$AE<BR>因為第二次是將 A 的值繼承 $AE 的提換結果，而非 $A 再加 E ﹗<BR>要解決此問題，我們可用更嚴謹的替換處理：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=BCD<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A=${A}E<BR>上例中，我們使用 {} 將變量名稱的範圍給明確定義出來，<BR>如此一來，我們就可以將 A 的變量值從 BCD 給擴充為 BCDE 。</DIV>
<DIV>(提示：關於 ${name} 事實上還可做到更多的變量處理能力，這些均屬於比較進階的變量處理，<BR>現階段暫時不介紹了，請大家自行參考資料。如 CU 的貼子：<BR><A href="http://www.chinaunix.net/forum/viewtopic.php?t=201843">http://www.chinaunix.net/forum/viewtopic.php?t=201843</A><BR>)</DIV>
<DIV>* export *</DIV>
<DIV>嚴格來說，我們在當前 shell 中所定義的變量，均屬於"本地變量"(local variable)，<BR>只有經過 export 命令的"輸出"處理，才能成為環境變量(environment variable)：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A=B<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ export A<BR>或：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ export A=B<BR>經過 export 輸出處理之後，變量 A 就能成為一個環境變量供其後的命令使用。<BR>在使用 export&nbsp; 的時侯，請別忘記 shell 在命令行對變量的"替換"(substitution)處理，<BR>比方說：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A=B<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ B=C<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ export $A<BR>上面的命令並未將 A 輸出為環境變量，而是將 B 作輸出，<BR>這是因為在這個命令行中，$A 會首先被提換出 B 然後再"塞回"作 export 的參數。</DIV>
<DIV>要理解這個 export ，事實上需要從 process 的角度來理解才能透徹。<BR>我將於下一章為大家說明 process 的觀念，敬請留意。</DIV>
<DIV>*取消變量*</DIV>
<DIV>要取消一個變量，在 bash 中可使用 unset 命令來處理：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unset A<BR>與 export 一樣，unset 命令行也同樣會作變量替換(這其實就是 shell 的功能之一)，<BR>因此：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A=B<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ B=C<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ unset $A<BR>事實上所取消的變量是 B 而不是 A 。</DIV>
<DIV>此外，變量一旦經過 unset 取消之後，其結果是將整個變量拿掉，而不僅是取消其變量值。<BR>如下兩行其實是很不一樣的：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A=<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ unset A<BR>第一行只是將變量 A 設定為"空值"(null&nbsp; value)，但第二行則讓變量 A 不在存在。<BR>雖然用眼睛來看，這兩種變量狀態在如下命令結果中都是一樣的：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ A=<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $A</DIV>
<DIV>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ unset A<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $A<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>請學員務必能識別 null value 與 unset 的本質區別，這在一些進階的變量處理上是很嚴格的。<BR>比方說：</DIV>
<DIV><BR>CODE:[Copy to clipboard]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ str=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 設為 null<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ var=${str=expr}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 定義 var<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $var<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $str<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ unset str&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 取消<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ var=${str=expr}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 定義 var<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $var<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expr<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ echo $str<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expr<BR>聰明的讀者(yes, you!)，稍加思考的話，<BR>應該不難發現為何同樣的 var=${str=expr} 在 null 與 unset 之下的不同吧？<BR>若你看不出來，那可能是如下原因之一：<BR>a. 你太笨了<BR>b. 不了解&nbsp; var=${str=expr}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 這個進階處理<BR>c. 對本篇說明還沒來得及消化吸收<BR>e. 我講得不好<BR>不知，你選哪個呢？....&nbsp; ^_^</DIV>
<DIV><BR>6) exec 跟 source 差在哪？</DIV>
<DIV>這次先讓我們從 CU Shell 版的一個實例貼子來談起吧：<BR>( <A href="http://www.chinaunix.net/forum/viewtopic.php?t=194191">http://www.chinaunix.net/forum/viewtopic.php?t=194191</A> )</DIV>
<DIV>例中的提問是：</DIV>
<DIV><BR>QUOTE:<BR>cd /etc/aa/bb/cc可以執行 <BR>但是把這條命令寫入shell時shell不執行！ <BR>這是什么原因呀！ <BR>我當時如何回答暫時別去深究，先讓我們了解一下行程(process)的觀念好了。<BR>首先，我們所執行的任何程式，都是由父行程(parent process)所產生出來的一個子行程(child process)，<BR>子行程在結束後，將返回到父行程去。此一現像在 Linux 系統中被稱為&nbsp; fork 。<BR>(為何要程為 fork 呢？嗯，畫一下圖或許比較好理解...&nbsp; ^_^ )<BR>當子行程被產生的時候，將會從父行程那裡獲得一定的資源分配、及(更重要的是)繼承父行程的環境﹗<BR>讓我們回到上一章所談到的"環境變量"吧：<BR>* 所謂環境變量其實就是那些會傳給子行程的變量。<BR>簡單而言，"遺傳性"就是區分本地變量與環境變量的決定性指標。<BR>然而，從遺傳的角度來看，我們也不難發現環境變量的另一個重要特徵：<BR>* 環境變量只能從父行程到子行程單向繼承。換句話說：在子行程中的環境如何變更，均不會影響父行程的環境。</DIV>
<DIV>接下來，再讓我們了解一下命令腳本(shell script)的概念。<BR>所謂的 shell script 講起來很簡單，就是將你平時在 shell prompt 後所輸入的多行 command line 依序寫入一個文件去而已。<BR>其中再加上一些條件判斷、互動界面、參數運用、函數調用、等等技巧，得以讓 script 更加"聰明"的執行，<BR>但若撇開這些技巧不談，我們真的可以簡單的看成 script 只不過依次執行預先寫好的命令行而已。</DIV>
<DIV>再結合以上兩個概念(process + script)，那應該就不難理解如下這句話的意思了：<BR>* 正常來說，當我們執行一個 shell script 時，其實是先產生一個 sub-shell 的子行程，然後 sub-shell 再去產生命令行的子行程。<BR>然則，那讓我們回到本章開始時所提到的例子再從新思考：</DIV>
<DIV><BR>QUOTE:<BR>cd /etc/aa/bb/cc可以執行 <BR>但是把這條命令寫入shell時shell不執行！ <BR>這是什么原因呀！ <BR>我當時的答案是這樣的：</DIV>
<DIV><BR>QUOTE:<BR>因為，一般我們跑的 shell script 是用 subshell 去執行的。 <BR>從 process 的觀念來看，是 parent process 產生一個 child process 去執行， <BR>當 child 結束後，會返回 parent ，但 parent 的環境是不會因 child 的改變而改變的。 <BR>所謂的環境元數很多，凡舉 effective id, variable, workding dir 等等... <BR>其中的 workding dir ($PWD) 正是樓主的疑問所在： <BR>當用 subshell 來跑 script 的話，sub shell 的 $PWD 會因為 cd 而變更， <BR>但當返回 primary shell 時，$PWD 是不會變更的。 <BR>能夠了解問題的原因及其原理是很好的，但是？如何解決問題恐怕是我們更感興趣的﹗是吧？^_^<BR>那好，接下來，再讓我們了解一下 source 命令好了。<BR>當你有了 fork 的概念之後，要理解 source 就不難：<BR>* 所謂 source 就是讓 script 在當前 shell 內執行、而不是產生一個 sub-shell 來執行。<BR>由於所有執行結果均於當前 shell 內完成，若 script 的環境有所改變，當然也會改變當前環境了﹗<BR>因此，只要我們要將原本單獨輸入的 script 命令行變成 source 命令的參數，就可輕易解決前例提到的問題了。<BR>比方說，原本我們是如此執行&nbsp; script 的：</DIV>
<DIV><BR>CODE:[Copy to clipboard]./my.script<BR>現在改成這樣即可：</DIV>
<DIV><BR>CODE:[Copy to clipboard]source ./my.script<BR>或：<BR>. ./my.script<BR>說到這裡，我想，各位有興趣看看 /etc 底下的眾多設定文件，<BR>應該不難理解它們被定議後，如何讓其他 script 讀取並繼承了吧？<BR>若然，日後你有機會寫自己的 script ，應也不難專門指定一個設定文件以供不同的 script 一起"共用"了...&nbsp; ^_^</DIV>
<DIV>okay，到這裡，若你搞得懂 fork 與 source 的不同，那接下來再接受一個挑戰：<BR>---- 那 exec 又與 source/fork 有何不同呢？<BR>哦... 要了解 exec 或許較為複雜，尤其扯上 File Descriptor 的話...<BR>不過，簡單來說：<BR>* exec 也是讓 script 在同一個行程上執行，但是原有行程則被結束了。<BR>也就是簡而言之：原有行程會否終止，就是 exec 與 source/fork 的最大差異了。</DIV>
<DIV>嗯，光是從理論去理解，或許沒那麼好消化，不如動手"實作+思考"來的印像深刻哦。<BR>下面讓我們寫兩個簡單的 script ，分別命令為 1.sh 及 2.sh ：</DIV>
<DIV>1.sh</DIV>
<DIV><BR>CODE:[Copy to clipboard]<BR>#!/bin/bash <BR>A=B <BR>echo "PID for 1.sh before exec/source/fork:$$"<BR>export A<BR>echo "1.sh: \$A is $A"<BR>case $1 in<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exec)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo "using exec..."<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exec ./2.sh ;;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo "using source..."<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . ./2.sh ;;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo "using fork by default..."<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ./2.sh ;;<BR>esac<BR>echo "PID for 1.sh after exec/source/fork:$$"<BR>echo "1.sh: \$A is $A"<BR>2.sh</DIV>
<DIV><BR>CODE:[Copy to clipboard]#!/bin/bash<BR>echo "PID for 2.sh: $$"<BR>echo "2.sh get \$A=$A from 1.sh"<BR>A=C<BR>export A<BR>echo "2.sh: \$A is $A"<BR>然後，分別跑如下參數來觀察結果：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ ./1.sh fork<BR>$ ./1.sh source<BR>$ ./1.sh exec<BR>或是，你也可以參考 CU 上的另一貼子：<BR><A href="http://www.chinaunix.net/forum/viewtopic.php?t=191051">http://www.chinaunix.net/forum/viewtopic.php?t=191051</A></DIV>
<DIV>好了，別忘了仔細比較輸出結果的不同及背後的原因哦...<BR>若有疑問，歡迎提出來一起討論討論~~~</DIV>
<DIV>happy scripting! ^_^ </DIV>
<DIV><BR>7) ( ) 與 { } 差在哪？ </DIV>
<DIV>嗯，這次輕鬆一下，不講太多...&nbsp; ^_^</DIV>
<DIV>先說一下，為何要用 ( ) 或 { } 好了。<BR>許多時候，我們在 shell 操作上，需要在一定條件下一次執行多個命令，<BR>也就是說，要麼不執行，要麼就全執行，而不是每次依序的判斷是否要執行下一個命令。<BR>或是，需要從一些命令執行優先次順中得到豁免，如算術的 2*(3+4) 那樣...<BR>這時候，我們就可引入"命令群組"(command group)的概念：將多個命令集中處理。</DIV>
<DIV>在 shell command line 中，一般人或許不太計較 ( ) 與 { } 這兩對符號的差異，<BR>雖然兩者都可將多個命令作群組化處理，但若從技術細節上，卻是很不一樣的：<BR>( ) 將 command group 置於 sub-shell 去執行，也稱 nested sub-shell。<BR>{ } 則是在同一個 shell 內完成，也稱為 non-named command group。<BR>若，你對上一章的 fork 與 source 的概念還記得了的話，那就不難理解兩者的差異了。<BR>要是在 command group 中扯上變量及其他環境的修改，我們可以根據不同的需求來使用 ( ) 或 { } 。<BR>通常而言，若所作的修改是臨時的，且不想影響原有或以後的設定，那我們就 nested sub-shell ，<BR>反之，則用 non-named command group 。</DIV>
<DIV>是的，光從 command line 來看，( ) 與 { } 的差別就講完了，夠輕鬆吧~~~&nbsp; ^_^<BR>然而，若這兩個 meta 用在其他 command meta 或領域中(如 Regular Expression)，還是有很多差別的。<BR>只是，我不打算再去說明了，留給讀者自己慢慢發掘好了...<BR>我這裡只想補充一個概念，就是 function 。<BR>所謂的 function ，就是用一個名字去命名一個&nbsp; command group ，然後再調用這個名字去執行 command group 。<BR>從 non-named command group 來推斷，大概你也可以猜到我要說的是 { } 了吧？(yes! 你真聰明﹗&nbsp; ^_^ )</DIV>
<DIV>在 bash 中，function 的定義方式有兩種：<BR>方式一：</DIV>
<DIV><BR>CODE:[Copy to clipboard]function function_name {<BR>&nbsp;&nbsp;&nbsp; command1<BR>&nbsp;&nbsp;&nbsp; command2<BR>&nbsp;&nbsp;&nbsp; command3<BR>&nbsp;&nbsp;&nbsp; ....<BR>}<BR>方式二：</DIV>
<DIV><BR>CODE:[Copy to clipboard]fuction_name () {<BR>&nbsp;&nbsp;&nbsp; command1<BR>&nbsp;&nbsp;&nbsp; command2<BR>&nbsp;&nbsp;&nbsp; command3<BR>&nbsp;&nbsp;&nbsp; ....<BR>}<BR>用哪一種方式無所謂，只是若碰到所定意的名稱與現有的命令或別名(Alias)衝突的話，方式二或許會失敗。<BR>但方式二起碼可以少打 function 這一串英文字母，對懶人來說(如我)，又何樂不為呢？...&nbsp; ^_^</DIV>
<DIV>function 在某一程度來說，也可稱為"函式"，但請不要與傳統編程所使用的函式(library)搞混了，畢竟兩者差異很大。<BR>惟一相同的是，我們都可以隨時用"已定義的名稱"來調用它們...<BR>若我們在 shell 操作中，需要不斷的重覆質行某些命令，我們首先想到的，或許是將命令寫成命令稿(shell script)。<BR>不過，我們也可以寫成 function ，然後在 command line 中打上 function_name 就可當一舨的 script 來使用了。<BR>只是若你在 shell 中定義的 function ，除了可用 unset function_name 取消外，一旦退出 shell ，function 也跟著取消。<BR>然而，在 script 中使用 function 卻有許多好處，除了可以提高整體 script 的執行效能外(因為已被載入)，<BR>還可以節省許多重覆的代碼...</DIV>
<DIV>簡單而言，若你會將多個命令寫成 script 以供調用的話，那，你可以將 function 看成是 script 中的 script ...&nbsp; ^_^<BR>而且，透過上一章介紹的 source 命令，我們可以自行定義許許多多好用的 function ，再集中寫在特定文件中，<BR>然後，在其他的 script 中用 source 將它們載入並反覆執行。<BR>若你是 RedHat Linux 的使用者，或許，已經猜得出 /etc/rc.d/init.d/functions 這個文件是作啥用的了~~~&nbsp; ^_^</DIV>
<DIV>okay，說要輕鬆點的嘛，那這次就暫時寫到這吧。祝大家學習愉快﹗&nbsp; ^_^ </DIV>
<DIV>8) $(( )) 與 $( ) 還有${ } 差在哪？ </DIV>
<DIV>我們上一章介紹了 ( ) 與 { } 的不同，這次讓我們擴展一下，看看更多的變化：$( ) 與 ${ } 又是啥玩意兒呢？</DIV>
<DIV>在 bash shell 中，$( ) 與 ` ` (反引號) 都是用來做命令替換用(command substitution)的。<BR>所謂的命令替換與我們第五章學過的變量替換差不多，都是用來重組命令行：<BR>* 完成引號裡的命令行，然後將其結果替換出來，再重組命令行。<BR>例如：<BR>[code]$ echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)[/code]<BR>如此便可方便得到上一星期天的日期了... ^_^</DIV>
<DIV>在操作上，用 $( ) 或 ` ` 都無所謂，只是我"個人"比較喜歡用 $( ) ，理由是：</DIV>
<DIV>1,&nbsp; ` ` 很容易與 ' ' ( 單引號)搞混亂，尤其對初學者來說。<BR>有時在一些奇怪的字形顯示中，兩種符號是一模一樣的(直豎兩點)。<BR>當然了，有經驗的朋友還是一眼就能分辯兩者。只是，若能更好的避免混亂，又何樂不為呢？ ^_^</DIV>
<DIV>2, 在多層次的復合替換中，` ` 須要額外的跳脫( \` )處理，而 $( ) 則比較直觀。例如：<BR>這是錯的：<BR>[code]command1 `command2 `command3` `[/code]<BR>原本的意圖是要在 command2 `command3` 先將 command3 提換出來給 command 2 處理，<BR>然後再將結果傳給 command1 `command2 ...` 來處理。<BR>然而，真正的結果在命令行中卻是分成了 `command2 ` 與 `` 兩段。<BR>正確的輸入應該如下：<BR>[code]command1 `command2 \`command3\` `[/code]</DIV>
<DIV>要不然，換成 $( ) 就沒問題了：<BR>[code]command1 $(command2 $(command3))[/code]<BR>只要你喜歡，做多少層的替換都沒問題啦~~~&nbsp; ^_^</DIV>
<DIV>不過，$( ) 並不是沒有斃端的...<BR>首先，` ` 基本上可用在全部的 unix shell 中使用，若寫成 shell script ，其移植性比較高。<BR>而 $( ) 並不見的每一種 shell 都能使用，我只能跟你說，若你用 bash2 的話，肯定沒問題...&nbsp; ^_^</DIV>
<DIV>接下來，再讓我們看 ${ } 吧... 它其實就是用來作變量替換用的啦。<BR>一般情況下，$var 與 ${var} 並沒有啥不一樣。<BR>但是用 ${ } 會比較精確的界定變量名稱的範圍，比方說：<BR>[code]$ A=B<BR>$ echo $AB</DIV>
<DIV>[/code]<BR>原本是打算先將 $A 的結果替換出來，然後再補一個 B 字母於其後，<BR>但在命令行上，真正的結果卻是只會提換變量名稱為 AB 的值出來...<BR>若使用 ${ } 就沒問題了：<BR>[code]$ echo ${A}B<BR>BB[/code]</DIV>
<DIV>不過，假如你只看到 ${ } 只能用來界定變量名稱的話，那你就實在太小看 bash 了﹗<BR>有興趣的話，你可先參考一下 cu 本版的精華文章：<BR><A href="http://www.chinaunix.net/forum/viewtopic.php?t=201843">http://www.chinaunix.net/forum/viewtopic.php?t=201843</A></DIV>
<DIV>為了完整起見，我這裡再用一些例子加以說明 ${ } 的一些特異功能：<BR>假設我們定義了一個變量為：<BR>file=/dir1/dir2/dir3/my.file.txt<BR>我們可以用 ${ } 分別替換獲得不同的值：<BR>${file#*/}：拿掉第一條 / 及其左邊的字串：dir1/dir2/dir3/my.file.txt<BR>${file##*/}：拿掉最後一條 / 及其左邊的字串：my.file.txt<BR>${file#*.}：拿掉第一個 .&nbsp; 及其左邊的字串：file.txt<BR>${file##*.}：拿掉最後一個 .&nbsp; 及其左邊的字串：txt<BR>${file%/*}：拿掉最後條 / 及其右邊的字串：/dir1/dir2/dir3<BR>${file%%/*}：拿掉第一條 / 及其右邊的字串：(空值)<BR>${file%.*}：拿掉最後一個 .&nbsp; 及其右邊的字串：/dir1/dir2/dir3/my.file<BR>${file%%.*}：拿掉第一個 .&nbsp; 及其右邊的字串：/dir1/dir2/dir3/my<BR>記憶的方法為：<BR>[list]# 是去掉左邊(在鑑盤上 # 在 $ 之左邊)<BR>% 是去掉右邊(在鑑盤上 % 在 $ 之右邊)<BR>單一符號是最小匹配﹔兩個符號是最大匹配。[/list]<BR>${file:0:5}：提取最左邊的 5 個字節：/dir1<BR>${file:5:5}：提取第 5 個字節右邊的連續 5 個字節：/dir2</DIV>
<DIV>我們也可以對變量值裡的字串作替換：<BR>${file/dir/path}：將第一個 dir 提換為 path：/path1/dir2/dir3/my.file.txt<BR>${file//dir/path}：將全部 dir 提換為 path：/path1/path2/path3/my.file.txt</DIV>
<DIV>利用 ${ } 還可針對不同的變數狀態賦值(沒設定、空值、非空值)： <BR>${file-my.file.txt} ：假如 $file 沒有設定，則使用 my.file.txt 作傳回值。(空值及非空值時不作處理) <BR>${file:-my.file.txt} ：假如 $file 沒有設定或為空值，則使用 my.file.txt 作傳回值。 (非空值時不作處理)<BR>${file+my.file.txt} ：假如 $file 設為空值或非空值，均使用 my.file.txt 作傳回值。(沒設定時不作處理)<BR>${file:+my.file.txt} ：若 $file 為非空值，則使用 my.file.txt 作傳回值。 (沒設定及空值時不作處理)<BR>${file=my.file.txt} ：若 $file 沒設定，則使用 my.file.txt 作傳回值，同時將 $file 賦值為 my.file.txt 。 (空值及非空值時不作處理)<BR>${file:=my.file.txt} ：若 $file 沒設定或為空值，則使用 my.file.txt 作傳回值，同時將 $file 賦值為 my.file.txt 。 (非空值時不作處理)<BR>${file?my.file.txt} ：若 $file 沒設定，則將 my.file.txt 輸出至 STDERR。 (空值及非空值時不作處理)<BR>${file:?my.file.txt} ：若 $file 沒設定或為空值，則將 my.file.txt 輸出至 STDERR。 (非空值時不作處理)</DIV>
<DIV>tips:<BR>以上的理解在於, 你一定要分清楚 unset 與 null 及 non-null 這三種賦值狀態.<BR>一般而言, : 與 null 有關, 若不帶 : 的話, null 不受影響, 若帶 : 則連 null 也受影響.</DIV>
<DIV><BR>還有哦，${#var} 可計算出變量值的長度：<BR>${#file} 可得到 27 ，因為 /dir1/dir2/dir3/my.file.txt 剛好是 27 個字節...</DIV>
<DIV>接下來，再為大家介稍一下 bash 的組數(array)處理方法。<BR>一般而言，A="a b c def" 這樣的變量只是將 $A 替換為一個單一的字串，<BR>但是改為 A=(a b c def) ，則是將 $A 定義為組數...<BR>bash 的組數替換方法可參考如下方法：<BR>${A[@]} 或 ${A[*]} 可得到 a b c def (全部組數)<BR>${A[0]} 可得到 a (第一個組數)，${A[1]} 則為第二個組數...<BR>${#A[@]} 或 ${#A[*]} 可得到 4 (全部組數數量)<BR>${#A[0]} 可得到 1 (即第一個組數(a)的長度)，${#A[3]} 可得到 3 (第四個組數(def)的長度)<BR>A[3]=xyz 則是將第四個組數重新定義為 xyz ...</DIV>
<DIV>諸如此類的.... <BR>能夠善用 bash 的 $( ) 與 ${ } 可大大提高及簡化 shell 在變量上的處理能力哦~~~&nbsp; ^_^</DIV>
<DIV>好了，最後為大家介紹 $(( )) 的用途吧：它是用來作整數運算的。<BR>在 bash 中，$(( )) 的整數運算符號大致有這些：<BR>+ - * / ：分別為 "加、減、乘、除"。<BR>% ：餘數運算<BR>&amp; | ^ !：分別為 "AND、OR、XOR、NOT" 運算。</DIV>
<DIV>例：<BR>[code]$ a=5; b=7; c=2<BR>$ echo $(( a+b*c ))<BR>19<BR>$ echo $(( (a+b)/c ))<BR>6<BR>$ echo $(( (a*b)%c))<BR>1[/code]</DIV>
<DIV>在 $(( )) 中的變量名稱，可於其前面加 $ 符號來替換，也可以不用，如：<BR>$(( $a + $b * $c)) 也可得到 19 的結果</DIV>
<DIV>此外，$(( )) 還可作不同進位(如二進位、八進位、十六進位)作運算呢，只是，輸出結果皆為十進位而已：<BR>echo $((16#2a)) 結果為 42 (16進位轉十進位)<BR>以一個實用的例子來看看吧：<BR>假如當前的&nbsp; umask 是 022 ，那麼新建文件的權限即為：<BR>[code]$ umask 022<BR>$ echo "obase=8;$(( 8#666 &amp; (8#777 ^ 8#$(umask)) ))" | bc<BR>644[/code] </DIV>
<DIV>事實上，單純用 (( )) 也可重定義變量值，或作 testing：<BR>a=5; ((a++)) 可將 $a 重定義為 6 <BR>a=5; ((a--)) 則為 a=4<BR>a=5; b=7; ((a &lt; b)) 會得到&nbsp; 0 (true) 的返回值。<BR>常見的用於 (( )) 的測試符號有如下這些：<BR>[list]&lt;：小於<BR>&gt;：大於<BR>&lt;=：小於或等於<BR>&gt;=：大於或等於<BR>==：等於<BR>!=：不等於[/list]<BR>不過，使用 (( )) 作整數測試時，請不要跟 [ ] 的整數測試搞混亂了。(更多的測試我將於第十章為大家介紹)</DIV>
<DIV>怎樣？好玩吧..&nbsp; ^_^&nbsp; okay，這次暫時說這麼多...<BR>上面的介紹，並沒有詳列每一種可用的狀態，更多的，就請讀者參考手冊文件囉...</DIV>
<DIV>9) $@ 與 $* 差在哪？ </DIV>
<DIV>要說 $@ 與 $* 之前，需得先從 shell script 的 positional parameter 談起...<BR>我們都已經知道變量(variable)是如何定義及替換的，這個不用再多講了。<BR>但是，我們還需要知道有些變量是 shell 內定的，且其名稱是我們不能隨意修改的，<BR>其中就有 positional parameter 在內。</DIV>
<DIV>在 shell script 中，我們可用 $0, $1, $2, $3 ... 這樣的變量分別提取命令行中的如下部份：</DIV>
<DIV><BR>CODE:[Copy to clipboard]script_name parameter1 parameter2 parameter3 ...<BR>我們很容易就能猜出 $0 就是代表 shell script 名稱(路逕)本身，而 $1 就是其後的第一個參數，如此類推....<BR>須得留意的是 IFS 的作用，也就是，若 IFS 被 quoting 處理後，那麼 positional parameter 也會改變。<BR>如下例：</DIV>
<DIV><BR>CODE:[Copy to clipboard]my.sh p1 "p2 p3" p4<BR>由於在 p2 與 p3 之間的空白鍵被 soft quote 所關閉了，因此 my.sh 中的 $2 是 "p2 p3" 而 $3 則是 p4 ...</DIV>
<DIV>還記得前兩章我們提到 fucntion 時，我不是說過它是 script 中的 script 嗎？&nbsp; ^_^<BR>是的，function 一樣可以讀取自己的(有別於 script 的) postitional parameter ，惟一例外的是 $0 而已。<BR>舉例而言：假設 my.sh 裡有一個 fucntion 叫 my_fun , 若在 script 中跑 my_fun fp1 fp2 fp3 ，<BR>那麼，function 內的 $0 是 my.sh ，而 $1 則是 fp1 而非 p1 了...</DIV>
<DIV>不如寫個簡單的 my.sh script&nbsp; 看看吧：</DIV>
<DIV><BR>CODE:[Copy to clipboard]#!/bin/bash</DIV>
<DIV>my_fun() {<BR>&nbsp;&nbsp;&nbsp; echo '$0 inside function is '$0<BR>&nbsp;&nbsp;&nbsp; echo '$1 inside function is '$1<BR>&nbsp;&nbsp;&nbsp; echo '$2 inside function is '$2<BR>}</DIV>
<DIV>echo '$0 outside function is '$0<BR>echo '$1 outside function is '$1<BR>echo '$2 outside function is '$2</DIV>
<DIV>my_fun fp1 "fp2 fp3"<BR>然後在 command line 中跑一下 script 就知道了：</DIV>
<DIV><BR>CODE:[Copy to clipboard]chmod +x my.sh<BR>./my.sh p1 "p2 p3"<BR>$0 outside function is ./my.sh<BR>$1 outside function is p1<BR>$2 outside function is p2 p3<BR>$0 inside function is ./my.sh<BR>$1 inside function is fp1<BR>$2 inside function is fp2 fp3<BR>然而，在使用 positional parameter 的時候，我們要注意一些陷阱哦：<BR>* $10 不是替換第 10 個參數，而是替換第一個參數($1)然後再補一個 0 於其後﹗<BR>也就是，my.sh one two three four five six seven eigth nine ten 這樣的 command line ，<BR>my.sh 裡的 $10 不是 ten 而是 one0 哦... 小心小心﹗<BR>要抓到 ten 的話，有兩種方法：</DIV>
<DIV>方法一是使用我們上一章介紹的 ${ } ，也就是用 ${10} 即可。</DIV>
<DIV>方法二，就是 shift 了。<BR>用通俗的說法來說，所謂的 shift 就是取消 positional parameter 中最左邊的參數( $0 不受影響)。<BR>其預設值為 1 ，也就是 shift 或 shift 1&nbsp; 都是取消 $1 ，而原本的 $2 則變成 $1、$3 變成 $2 ...<BR>若 shift 3 則是取消前面三個參數，也就是原本的 $4 將變成 $1 ...<BR>那，親愛的讀者，你說要 shift 掉多少個參數，才可用 $1 取得 ${10} 呢？ ^_^</DIV>
<DIV>okay，當我們對 positional parameter 有了基本概念之後，那再讓我們看看其他相關變量吧。<BR>首先是 $# ：它可抓出 positional parameter 的數量。<BR>以前面的 my.sh p1 "p2 p3" 為例：<BR>由於 p2 與 p3 之間的 IFS 是在 soft quote 中，因此 $# 可得到 2 的值。<BR>但如果 p2 與 p3 沒有置於 quoting 中話，那 $# 就可得到 3 的值了。<BR>同樣的道理在 function 中也是一樣的...</DIV>
<DIV>因此，我們常在 shell script 裡用如下方法測試 script 是否有讀進參數：</DIV>
<DIV><BR>CODE:[Copy to clipboard][ $# = 0 ]<BR>假如為 0 ，那就表示 script 沒有參數，否則就是有帶參數...</DIV>
<DIV>接下來就是 $@ 與 $* ：<BR>精確來講，兩者只有在 soft quote 中才有差異，否則，都表示"全部參數"( $0 除外)。<BR>舉例來說好了：<BR>若在 command line 上跑 my.sh p1 "p2 p3" p4 的話，<BR>不管是 $@ 還是 $* ，都可得到 p1 p2 p3 p4 就是了。<BR>但是，如果置於 soft quote 中的話：<BR>"$@" 則可得到 "p1" "p2 p3" "p4" 這三個不同的詞段(word)﹔<BR>"$*" 則可得到 "p1 p2 p3 p4" 這一整串單一的詞段。</DIV>
<DIV>我們可修改一下前面的 my.sh ，使之內容如下：</DIV>
<DIV><BR>CODE:[Copy to clipboard]#!/bin/bash</DIV>
<DIV>my_fun() {<BR>&nbsp;&nbsp;&nbsp; echo "$#"<BR>}</DIV>
<DIV>echo 'the number of parameter in "$@" is '$(my_fun "$@")<BR>echo 'the number of parameter in "$*" is '$(my_fun "$*")<BR>然後再執行 ./my.sh p1 "p2 p3" p4 就知道 $@ 與 $* 差在哪了 ...&nbsp;&nbsp;&nbsp; ^_^ </DIV>
<DIV><BR>10) &amp;&amp; 與 || 差在哪？ </DIV>
<DIV>好不容易，進入兩位數的章節了... 一路走來，很辛苦吧？也很快樂吧？&nbsp; ^_^</DIV>
<DIV>在解答本章題目之前，先讓我們了解一個概念：return value ﹗<BR>我們在 shell 下跑的每一個 command 或 function ，在結束的時候都會傳回父行程一個值，稱為 return value 。<BR>在 shell command line 中可用 $? 這個變量得到最"新"的一個 return value ，也就是剛結束的那個行程傳回的值。<BR>Return Value(RV) 的取值為 0-255 之間，由程式(或 script)的作者自行定議：<BR>* 若在 script 裡，用 exit RV 來指定其值，若沒指定，在結束時以最後一道命令之 RV 為值。<BR>* 若在 function 裡，則用 return RV 來代替 exit RV 即可。</DIV>
<DIV>Return Value 的作用，是用來判斷行程的退出狀態(exit status)，只有兩種：<BR>* 0 的話為"真"( true )<BR>* 非&nbsp; 0 的話為"假"( false )</DIV>
<DIV>舉個例子來說明好了：<BR>假設當前目錄內有一份 my.file 的文件，而 no.file 是不存在的：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ touch my.file<BR>$ ls my.file<BR>$ echo $?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # first echo<BR>0<BR>$ ls no.file<BR>ls: no.file: No such file or directory<BR>$ echo $?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # second echo<BR>1<BR>$ echo $?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # third echo<BR>0<BR>上例的第一個 echo 是關於 ls my.file 的 RV ，可得到 0 的值，因此為 true ﹔<BR>第二個 echo 是關於 ls no.file 的 RV ，則得到非 0&nbsp; 的值，因此為 false ﹔<BR>第三個 echo 是關於第二個 echo $? 的 RV ，為 0 的值，因此也為 true 。</DIV>
<DIV>請記住：每一個 command 在結束時都會送回 return value 的﹗不管你跑甚麼樣的命令...<BR>然而，有一個命令卻是"專門"用來測試某一條件而送出 return value 以供 true 或 false 的判斷，<BR>它就是 test 命令了﹗<BR>若你用的是 bash ，請在 command line 下打 man test 或 man bash 來了解這個 test 的用法。<BR>這是你可用作參考的最精確的文件了，要是聽別人說的，僅作參考就好... <BR>下面我只簡單作一些輔助說明，其餘的一律以 man 為準：</DIV>
<DIV>首先，test 的表示式我們稱為 expression ，其命令格式有兩種：</DIV>
<DIV><BR>CODE:[Copy to clipboard]test expression <BR>or:<BR>[ expression ]<BR>(請務必注意 [ ] 之間的空白鍵﹗)<BR>用哪一種格式沒所謂，都是一樣的效果。(我個人比較喜歡後者...)</DIV>
<DIV>其次，bash 的 test 目前支援的測試對像只有三種：<BR>* string：字串，也就是純文字。<BR>* integer：整數( 0 或正整數，不含負數或小數點)。<BR>* file：文件。<BR>請初學者一定要搞清楚這三者的差異，因為 test 所用的 expression 是不一樣的。<BR>以 A=123 這個變量為例：<BR>* [ "$A" = 123 ]：是字串的測試，以測試 $A 是否為 1、2、3 這三個連續的"文字"。<BR>* [ "$A" -eq 123 ]：是整數的測試，以測試 $A 是否等於"一百二十三"。<BR>* [ -e "$A" ]：是關於文件的測試，以測試 123 這份"文件"是否存在。 </DIV>
<DIV>第三，當 expression 測試為"真"時，test 就送回 0 (true) 的 return value ，否則送出非 0 (false)。<BR>若在 expression 之前加上一個 " ! "(感嘆號)，則是當 expression 為"假時" 才送出 0 ，否則送出非 0 。<BR>同時，test 也允許多重的覆合測試：<BR>* expression1 -a expression2 ：當兩個 exrepssion 都為 true ，才送出 0 ，否則送出非 0 。<BR>* expression1 -o expression2 ：只需其中一個 exrepssion 為 true ，就送出 0 ，只有兩者都為 false 才送出非 0 。<BR>例如：</DIV>
<DIV><BR>CODE:[Copy to clipboard][ -d "$file" -a -x "$file" ]<BR>是表示當 $file 是一個目錄、且同時具有 x 權限時，test 才會為 true 。</DIV>
<DIV>第四，在 command line 中使用 test 時，請別忘記命令行的"重組"特性，<BR>也就是在碰到 meta 時會先處理 meta 再重新組建命令行。(這個特性我在第二及第四章都曾反覆強調過)<BR>比方說，若 test 碰到變量或命令替換時，若不能滿足 expression 格式時，將會得到語法錯誤的結果。<BR>舉例來說好了：<BR>關於 [ string1 = string2 ] 這個 test 格式，<BR>在 = 號兩邊必須要有字串，其中包括空(null)字串(可用 soft quote&nbsp; 或 hard quote 取得)。<BR>假如 $A 目前沒有定義，或被定議為空字串的話，那如下的寫法將會失敗：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ unset A<BR>$ [ $A = abc ]<BR>[: =: unary operator expected<BR>這是因為命令行碰到&nbsp; $ 這個 meta 時，會替換 $A 的值，然後再重組命令行，那就變成了：<BR>[ = abc ]<BR>如此一來 = 號左邊就沒有字串存在了，因此造成 test 的語法錯誤﹗<BR>但是，下面這個寫法則是成立的：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ [ "$A" = abc ]<BR>$ echo $?<BR>1<BR>這是因為在命令行重組後的結果為：<BR>[ "" = abc ]<BR>由於 = 左邊我們用 soft quote 得到一個空字串，而讓 test 語法得以通過... </DIV>
<DIV>讀者諸君請務必留意這些細節哦，因為稍一不慎，將會導至 test 的結果變了個樣﹗<BR>若您對 test 還不是很有經驗的話，那在使用 test 時不妨先採用如下這一個"法則"：<BR>* 假如在 test 中碰到變量替換，用 soft quote 是最保險的﹗<BR>若你對 quoting 不熟的話，請重新溫習第四章的內容吧...&nbsp; ^_^</DIV>
<DIV>okay，關於更多的 test 用法，老話一句：請看 man page 吧﹗&nbsp; ^_^</DIV>
<DIV>雖然洋洋灑灑講了一大堆，或許你還在嘀咕.... 那... 那個 return value 有啥用啊？﹗<BR>問得好﹗<BR>告訴你：return value 的作用可大了﹗若你想讓你的 shell 變"聰明"的話，就全靠它了：<BR>* 有了 return value，我們可以讓 shell 跟據不同的狀態做不同的時情...</DIV>
<DIV>這時候，才讓我來揭曉本章的答案吧~~~&nbsp; ^_^<BR>&amp;&amp; 與 || 都是用來"組建"多個 command line 用的：<BR>* command1 &amp;&amp; command2 ：其意思是 command2 只有在 RV 為 0 (true) 的條件下執行。<BR>* command1 || command2 ：其意思是 command2 只有在 RV 為非 0 (false) 的條件下執行。<BR>來，以例子來說好了：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ A=123<BR>$ [ -n "$A" ] &amp;&amp; echo "yes! it's ture."<BR>yes! it's ture.<BR>$ unset A<BR>$ [ -n "$A" ] &amp;&amp; echo "yes! it's ture."<BR>$ [ -n "$A" ] || echo "no, it's NOT ture."<BR>no, it's NOT ture.<BR>(註：[ -n string ] 是測試 string 長度大於 0 則為 true 。)<BR>上例的第一個 &amp;&amp; 命令行之所以會執行其右邊的 echo 命令，是因為上一個 test 送回了 0 的 RV 值﹔<BR>但第二次就不會執行，因為為 test 送回非 0 的結果...<BR>同理，|| 右邊的 echo 會被執行，卻正是因為左邊的 test 送回非 0 所引起的。</DIV>
<DIV>事實上，我們在同一命令行中，可用多個 &amp;&amp; 或 || 來組建呢：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ A=123<BR>$ [ -n "$A" ] &amp;&amp; echo "yes! it's ture." || echo "no, it's NOT ture."<BR>yes! it's ture.<BR>$ unset A<BR>$ [ -n "$A" ] &amp;&amp; echo "yes! it's ture." || echo "no, it's NOT ture."<BR>no, it's NOT ture.<BR>怎樣，從這一刻開始，你是否覺得我們的 shell 是"很聰明"的呢？&nbsp; ^_^</DIV>
<DIV>好了，最後，佈置一道習題給大家做做看、、、<BR>下面的判斷是：當 $A 被賦與值時，再看是否小於 100 ，否則送出 too big! ：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ A=123<BR>$ [ -n "$A" ] &amp;&amp; [ "$A" -lt 100 ] || echo 'too big!'<BR>too big!<BR>若我將 A 取消，照理說，應該不會送文字才對啊(因為第一個條件就不成立了)...</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ unset A<BR>$ [ -n "$A" ] &amp;&amp; [ "$A" -lt 100 ] || echo 'too big!'<BR>too big!<BR>為何上面的結果也可得到呢？<BR>又，如何解決之呢？<BR>(提示：修改方法很多，其中一種方法可利用第七章介紹過的 command group ...)</DIV>
<DIV>快﹗告我我答案﹗其餘免談.... </DIV>
<DIV><BR>11) &gt; 與 &lt; 差在哪？ </DIV>
<DIV>這次的題目之前我在 CU 的 shell 版已說明過了：<BR><A href="http://bbs.chinaunix.net/forum/24/20031030/191375.html">http://bbs.chinaunix.net/forum/24/20031030/191375.html</A><BR>這次我就不重寫了，將貼子的內容"抄"下來就是了...</DIV>
<DIV>--------------<BR>11.1<BR>談到 I/O redirection ，不妨先讓我們認識一下 File Descriptor (FD) 。 </DIV>
<DIV>程式的運算，在大部份情況下都是進行數據(data)的處理， <BR>這些數據從哪讀進？又，送出到哪裡呢？ <BR>這就是 file descriptor (FD) 的功用了。 </DIV>
<DIV>在 shell 程式中，最常使用的 FD 大概有三個，分別為： <BR>0: Standard Input (STDIN) <BR>1: Standard Output (STDOUT) <BR>2: Standard Error Output (STDERR) </DIV>
<DIV>在標準情況下，這些 FD 分別跟如下設備(device)關聯： <BR>stdin(0): keyboard <BR>stdout(1): monitor <BR>stderr(2): monitor </DIV>
<DIV>我們可以用如下下命令測試一下：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ mail -s test root <BR>this is a test mail. <BR>please skip. <BR>^d (同時按 crtl 跟 d 鍵) <BR>很明顯，mail 程式所讀進的數據，就是從 stdin 也就是 keyboard 讀進的。 <BR>不過，不見得每個程式的 stdin 都跟 mail 一樣從 keyboard 讀進， <BR>因為程式作者可以從檔案參數讀進 stdin ，如：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ cat /etc/passwd <BR>但，要是 cat 之後沒有檔案參數則又如何呢？ <BR>哦，請您自己玩玩看囉.... ^_^</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ cat <BR>(請留意數據輸出到哪裡去了，最後別忘了按 ^d 離開...) </DIV>
<DIV>至於 stdout 與 stderr ，嗯... 等我有空再續吧... ^_^ <BR>還是，有哪位前輩要來玩接龍呢？ </DIV>
<DIV>--------------<BR>11.2<BR>沿文再續，書接上一回... ^_^ </DIV>
<DIV>相信，經過上一個練習後，你對 stdin 與 stdout 應該不難理解吧？ <BR>然後，讓我們繼續看 stderr 好了。 <BR>事實上，stderr 沒甚麼難理解的：說穿了就是"錯誤信息"要往哪邊送而已... <BR>比方說，若讀進的檔案參數是不存在的，那我們在 monitor 上就看到了：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ ls no.such.file <BR>ls: no.such.file: No such file or directory <BR>若，一個命令同時產生 stdout 與 stderr 呢？ <BR>那還不簡單，都送到 monitor 來就好了：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ touch my.file <BR>$ ls my.file no.such.file <BR>ls: no.such.file: No such file or directory <BR>my.file <BR>okay，至此，關於 FD 及其名稱、還有相關聯的設備，相信你已經沒問題了吧？ <BR>那好，接下來讓我們看看如何改變這些 FD 的預設數據通道， <BR>我們可用 &lt; 來改變讀進的數據通道(stdin)，使之從指定的檔案讀進。 <BR>我們可用 &gt; 來改變送出的數據通道(stdout, stderr)，使之輸出到指定的檔案。 </DIV>
<DIV>比方說：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ cat &lt; my.file <BR>就是從 my.file 讀進數據</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ mail -s test root &lt; /etc/passwd <BR>則是從 /etc/passwd 讀進... <BR>這樣一來，stdin 將不再是從 keyboard 讀進，而是從檔案讀進了... <BR>嚴格來說，&lt; 符號之前需要指定一個 FD 的(之間不能有空白)， <BR>但因為 0 是 &lt; 的預設值，因此 &lt; 與 0&lt; 是一樣的﹗ </DIV>
<DIV>okay，這個好理解吧？ <BR>那，要是用兩個 &lt;&lt; 又是啥呢？ <BR>這是所謂的 HERE Document ，它可以讓我們輸入一段文本，直到讀到 &lt;&lt; 後指定的字串。 <BR>比方說：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ cat &lt;&lt;FINISH <BR>first line here <BR>second line there <BR>third line nowhere <BR>FINISH <BR>這樣的話，cat 會讀進 3 行句子，而無需從 keyboard 讀進數據且要等 ^d 結束輸入。 </DIV>
<DIV>至於 &gt; 又如何呢？ <BR>且聽下回分解....</DIV>
<DIV>--------------<BR>11.3<BR>okay，又到講古時間~~~ </DIV>
<DIV>當你搞懂了 0&lt; 原來就是改變 stdin 的數據輸入通道之後，相信要理解如下兩個 redirection 就不難了： <BR>* 1&gt; <BR>* 2&gt; <BR>前者是改變 stdout 的數據輸出通道，後者是改變 stderr 的數據輸出通道。 <BR>兩者都是將原本要送出到 monitor 的數據轉向輸出到指定檔案去。 <BR>由於 1 是 &gt; 的預設值，因此，1&gt; 與 &gt; 是相同的，都是改 stdout 。 </DIV>
<DIV>用上次的 ls 例子來說明一下好了：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ ls my.file no.such.file 1&gt;file.out <BR>ls: no.such.file: No such file or directory <BR>這樣 monitor 就只剩下 stderr 而已。因為 stdout 給寫進 file.out 去了。</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ ls my.file no.such.file 2&gt;file.err <BR>my.file <BR>這樣 monitor 就只剩下 stdout ，因為 stderr 寫進了 file.err 。</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ ls my.file no.such.file 1&gt;file.out 2&gt;file.err <BR>這樣 monitor 就啥也沒有，因為 stdout 與 stderr 都給轉到檔案去了... </DIV>
<DIV>呵~~~ 看來要理解 &gt; 一點也不難啦﹗是不？沒騙你吧？ ^_^ <BR>不過，有些地方還是要注意一下的。 </DIV>
<DIV>首先，是同時寫入的問題。比方如下這個例子：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ ls my.file no.such.file 1&gt;file.both 2&gt;file.both <BR>假如 stdout(1) 與 stderr(2) 都同時在寫入 file.both 的話， <BR>則是採取“覆蓋”方式：後來寫入的覆蓋前面的。 <BR>讓我們假設一個 stdout 與 stderr 同時寫入 file.out 的情形好了： <BR>* 首先 stdout 寫入10個字元 <BR>* 然後 stderr 寫入 6 個字元<BR>那麼，這時候原本 stdout 的前面 6 個字元就被 stderr 覆蓋掉了。</DIV>
<DIV>那，如何解決呢？所謂山不轉路轉、路不轉人轉嘛， <BR>我們可以換一個思維：將 stderr 導進 stdout 或將 stdout 導進 sterr ，而不是大家在搶同一份檔案，不就行了﹗ <BR>bingo﹗就是這樣啦： <BR>* 2&gt;&amp;1 就是將 stderr 併進 stdout 作輸出 <BR>* 1&gt;&amp;2 或 &gt;&amp;2 就是將 stdout 併進 stderr 作輸出 <BR>於是，前面的錯誤操作可以改為：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ ls my.file no.such.file 1&gt;file.both 2&gt;&amp;1 <BR>或 <BR>$ ls my.file no.such.file 2&gt;file.both &gt;&amp;2 <BR>這樣，不就皆大歡喜了嗎？ 呵~~~ ^_^ </DIV>
<DIV>不過，光解決了同時寫入的問題還不夠，我們還有其他技巧需要了解的。 <BR>故事還沒結束，別走開﹗廣告後，我們再回來...﹗</DIV>
<DIV><BR>--------------<BR>11.4<BR>okay，這次不講 I/O Redirction ，講佛吧... <BR>(有沒搞錯？﹗網中人是否頭殼燒壞了？...) 嘻~~~ ^_^ </DIV>
<DIV>學佛的最高境界，就是"四大皆空"。至於是空哪四大塊？我也不知，因為我還沒到那境界... <BR>但這個"空"字，卻非常值得我們返複把玩的： <BR>--- 色即是空、空即是色﹗ <BR>好了，施主要是能夠領會"空"的禪意，那離修成正果不遠矣~~~ </DIV>
<DIV>在 Linux 檔案系統裡，有個設備檔位於 /dev/null 。 <BR>許多人都問過我那是甚麼玩意兒？我跟你說好了：那就是"空"啦﹗ <BR>沒錯﹗空空如也的空就是 null 了.... 請問施主是否忽然有所頓誤了呢？然則恭喜了~~~ ^_^ </DIV>
<DIV>這個 null 在 I/O Redirection 中可有用得很呢： <BR>* 若將 FD1 跟 FD2 轉到 /dev/null 去，就可將 stdout 與 stderr 弄不見掉。 <BR>* 若將 FD0 接到 /dev/null 來，那就是讀進 nothing 。 <BR>比方說，當我們在執行一個程式時，畫面會同時送出 stdout 跟 stderr ， <BR>假如你不想看到 stderr (也不想存到檔案去)，那可以：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ ls my.file no.such.file 2&gt;/dev/null <BR>my.file<BR>若要相反：只想看到 stderr 呢？還不簡單﹗將 stdout 弄到 null 就行：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ ls my.file no.such.file &gt;/dev/null <BR>ls: no.such.file: No such file or directory <BR>那接下來，假如單純只跑程式，不想看到任何輸出結果呢？ <BR>哦，這裡留了一手上次節目沒講的法子，專門贈予有緣人﹗... ^_^ <BR>除了用 &gt;/dev/null 2&gt;&amp;1 之外，你還可以如此：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ ls my.file no.such.file &amp;&gt;/dev/null <BR>(提示：將 &amp;&gt; 換成 &gt;&amp; 也行啦~~! ) </DIV>
<DIV>okay？講完佛，接下來，再讓我們看看如下情況：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ echo "1" &gt; file.out <BR>$ cat file.out <BR>1 <BR>$ echo "2" &gt; file.out <BR>$ cat file.out <BR>2 <BR>看來，我們在重導 stdout 或 stderr 進一份檔案時，似乎永遠只獲得最後一次導入的結果。 <BR>那，之前的內容呢？ <BR>呵~~~ 要解決這個問提很簡單啦，將 &gt; 換成 &gt;&gt; 就好：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ echo "3" &gt;&gt; file.out <BR>$ cat file.out <BR>2 <BR>3 <BR>如此一來，被重導的目標檔案之內容並不會失去，而新的內容則一直增加在最後面去。 <BR>easy ？ 呵 ... ^_^ </DIV>
<DIV>但，只要你再一次用回單一的 &gt; 來重導的話，那麼，舊的內容還是會被"洗"掉的﹗ <BR>這時，你要如何避免呢？ <BR>----備份﹗ yes ，我聽到了﹗不過.... 還有更好的嗎？ <BR>既然與施主這麼有緣份，老納就送你一個錦囊妙法吧：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ set -o noclobber <BR>$ echo "4" &gt; file.out <BR>-bash: file: cannot overwrite existing file <BR>那，要如何取消這個"限制"呢？ <BR>哦，將 set -o 換成 set +o 就行：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ set +o noclobber <BR>$ echo "5" &gt; file.out <BR>$ cat file.out <BR>5 <BR>再問：那... 有辦法不取消而又"臨時"蓋寫目標檔案嗎？ <BR>哦，佛曰：不可告也﹗ <BR>啊~~~ 開玩笑的、開玩笑的啦~~~ ^_^ 唉，早就料到人心是不足的了﹗</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ set -o noclobber <BR>$ echo "6" &gt;| file.out <BR>$ cat file.out <BR>6 <BR>留意到沒有：在 &gt; 後面再加個" | "就好(注意： &gt; 與 | 之間不能有空白哦).... </DIV>
<DIV>呼.... (深呼吸吐納一下吧)~~~ ^_^ <BR>再來還有一個難題要你去參透的呢：</DIV>
<DIV><BR>CODE:[Copy to clipboard]$ echo "some text here" &gt; file <BR>$ cat &lt; file <BR>some text here <BR>$ cat &lt; file &gt; file.bak <BR>$ cat &lt; file.bak <BR>some text here <BR>$ cat &lt; file &gt; file <BR>$ cat &lt; file <BR>嗯？﹗注意到沒有？﹗﹗ <BR>---- 怎麼最後那個 cat 命令看到的 file 竟是空的？﹗ <BR>why? why? why? </DIV>
<DIV>同學們：下節課不要遲到囉~~~!</DIV>
<DIV><BR>--------------<BR>11.5<BR>噹噹噹~~~ 上課囉~~~ ^_^ </DIV>
<DIV>前面提到：$ cat &lt; file &gt; file 之後原本有內容的檔案結果卻被洗掉了﹗ <BR>要理解這一現像其實不難，這只是 priority 的問%E  ]]></description>
		</item>	
			<item>
			<title><![CDATA[vmware oracle 10 on windows 安装手册]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=231612]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Sat, 13 Jan 2007 13:30:21 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV>VMware windows oracle 10g rac安装<BR>(1)硬件配置<BR>DELL 2900服务器,CPU 1.6G*2 内存:2G 硬盘173G.<BR>安装Windows 2003操作系统和VMWARE SERVER1.O<BR>(2)虚拟机规划<BR>操作系统:Windows2003<BR>Oracle版本:Oracle 10g<BR>网卡:2块<BR>内存:512M<BR>Cluster软件:Oracle Clusterware<BR>(3)安装第一台虚拟机<BR>(a)安装Windows 2003操作系统<BR>(b)机器名:RAC1 <BR>(C)IP address:192.168.1.100(Public)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10.0.0.1(Private)<BR>(d)修改hosts……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[VMWARE LINUX RAC 安装手册]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=206181]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Sat, 25 Nov 2006 15:57:59 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV><FONT size=2>(1)硬件环境<BR>HP DL380服务器 CPU 3.0*2 内存：4G 硬盘：100G<BR>(2)软件环境<BR>RedHat AS3 (使用其他的RedHat版本也可以，但是要注意，下载对应的OCFS软件)<BR>Vmware gsx 3.0<BR>(3)安装vmware gsx 3.0和一个RedHat AS3的操作系统，<BR>具体方法很多资料都有，不在重复。<BR>(4)修改/etc/sysctl.conf<BR>net.core.rmem_default = 262144<BR>net.core.rmem_max = 262144<BR>net.core.wmem_default = 262144<BR>net.core.rmem_max = 262144<BR>net.ipv4.tcp_sack=0 <BR>net.ipv4.tcp_timestamps=0<BR>fs.file-max = ……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[ORACLE数据库在线备份原理 ]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=200680]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Wed, 15 Nov 2006 06:08:38 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><B><SPAN lang=EN-US style="FONT-SIZE: 15pt; mso-bidi-font-size: 12.0pt"><FONT face="Times New Roman">ORACLE</FONT></SPAN></B><B><SPAN style="FONT-SIZE: 15pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">数据库在线备份原理</SPAN></B><B><SPAN style="FONT-SIZE: 15pt; mso-bidi-font-size: 12.0pt"><FONT face="Times New Roman"> <SPA……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[10g RMAN 新特性as compressed backupset的测试 ]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=194957]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Fri, 03 Nov 2006 09:58:27 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV>
<DIV class=storytext>
<P>AIX 5303, ORACLE 10202</P>
<P>数据库的RMAN备份占用了很多磁盘空间，而且还随数据量的增长而增长，现已经占用了</P>
<P>130 G，比4月份的90G涨了40G，我担心到年底，专门保存备份集的/orabak 目录的磁盘空间</P>
<P>会爆满。昨天考虑，测试一下10G中RMAN的新特性：使用了RMAN 的压缩功能。今早查看，压缩效果还是比较明显的，</P><BR>
<P>由原来的130G，下降到目前的20G左右。但时间却大大增加：由原来的40分钟，涨到155分钟。昨天备份后，占用的磁盘情况</P>
<P>$ df -g<BR>文件系统 GB 块 可用……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[RMAN快速入门指南]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=194482]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Thu, 02 Nov 2006 13:14:44 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV>由于oracle9i以后exp 不再支持 inctype ，在不脱机情况下增量备份只有靠rman来实现，所以搜集了一些网上rman的资料供大家参考。</DIV>
<DIV>一、Oracle RMAN快速入门指南<BR>前言<BR>这篇文章主要介绍RMAN的常用方法，其中包含了作者一些自己的经验，里面的实验也基本全在WIN 2K和ORACLE 8.1.6环境下测试成功（因为这个环境比较容易实现）。</DIV>
<DIV>本文借鉴了网上一些高手的相关文章，希望大侠们不要见怪，此处一并谢过。</DIV>
<DIV>这篇文章主要是在北京出差期间写的，回到家后整理修改了一下，时间比较仓促，同时因为篇幅……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[oracle logminer]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=192675]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Mon, 30 Oct 2006 14:09:42 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV align=center><FONT size=3><STRONG>oracle logminer 配置</STRONG></FONT></DIV>
<DIV>Oracle Logminer配置主要分下面几个步骤</DIV>
<DIV>1.&nbsp; 安装LogMiner<BR>2.&nbsp; 创建LogMiner所需的数据字典文件<BR>3.&nbsp; 添加要分析的日志文件<BR>4.&nbsp; 开始日志分析<BR>5.&nbsp; 查看分析结果</DIV>
<DIV>&nbsp;</DIV>
<DIV>安装LogMiner</DIV>
<DIV>&nbsp;LogMiner工具实际上是由两个PL/SQL内建包（(DBMS_LOGMNR 和 DBMS_ LOGMNR_D）和四个V$动态性能视图（视图是在利用过程DBMS_LOGMNR.START_LOGMNR启动LogMiner时创建……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[Solaris Apache tomcat php jdk融合]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=148984]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Tue, 01 Aug 2006 04:39:09 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV>首先我们要修改/usr/local/apache2/conf/httpd.conf</DIV>
<DIV>LoadModule jk_module&nbsp; modules/mod_jk.so<BR>JkWorkersFile conf/workers.properties<BR>JkLogFile logs/mod_jk.log<BR>JkLogLevel info<BR>JkMount /*.jsp worker1<BR>JkMount /*/servlet/ worker1</DIV>
<DIV>然后我们在/usr/local/apache2/conf/workers.properties</DIV>
<DIV>worker.list=worker1<BR>worker.worker1.type=ajp13<BR>worker.worker1.host=localhost<BR>worker.worker1.port=8009</DIV>
<DIV>最近我们在/usr/local/apach2/htdocs/test.jsp<……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[Linux Oracle OCFS RAC 安装  ]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=138200]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Sun, 09 Jul 2006 04:43:39 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV><SPAN style="FONT-SIZE: 13px">Linux Oracle OCFS RAC 安装&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[RMAN复制数据库]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=138199]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Sun, 09 Jul 2006 04:40:47 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV>在实际工作中，很多时候都会用RMAN备份，我们需要在异机恢复数据库，用来测试备份。<BR>在日常的工作中我们有很多种方法来clone一个数据库，用RMAN非常简单和方便<BR>（1）数据环境<BR>OS:RedHat AS3<BR>database:Oracle 9.2.4<BR>Oracle_sid:db2<BR>我希望用RMAN在本机COLNE一个数据库db3<BR>数据文件存放位置为/oradata/db3<BR>(2)创建$ORACLE_BASE/admin/db3目录，然后建立dbump,udump,pfile的子目录<BR>(3)创建$ORACLE_BASE/admin/db3/pfile/initdb3.ora文件如下<BR>&nbsp;####################################################……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[Windows ORACLE 9I OCFS RAC ]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=129458]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Sat, 25 Nov 2006 16:25:42 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Windows ORACLE 9I OCFS RAC VMWARE 安装<BR>(1)硬件环境<BR>HP DL380服务器 CPU 3.0*2 内存：4G 硬盘：100G<BR>(2)软件环境<BR>Windows 2000 Profession (使用Winodws XP 2003等系统一样的方法)<BR>Vmware gsx 3.0<BR>(3)安装vmware gsx 3.0和一个Windows 2000 profession的操作系统，<BR>具体方法很多资料都有，不在重复。<BR>(4)拷贝上面安装的系统，重新更改机器……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[RMAN备份恢复试验]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=100435]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Sat, 15 Apr 2006 14:45:16 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV align=center>Rman备份恢复试验</DIV>
<DIV align=left>试验环境:</DIV>
<DIV align=left>RedHat AS3</DIV>
<DIV align=left>Oracle 9i</DIV>
<DIV align=left>Oracle_SID:RAC3</DIV>
<DIV align=left>没有使用catalog</DIV>
<DIV align=left>我们使用rman备份</DIV>
<DIV align=left>run</DIV>
<DIV align=left>{</DIV>
<DIV align=left>allocate channel ch1 type disk</DIV>
<DIV align=left>backup (database);</DIV>
<DIV align=left>backup (current controlfile);</DIV>
<DIV align=left>backup (archivelog all)……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[Oracle 9 手工建库]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=97850]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Mon, 10 Apr 2006 10:21:01 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[<DIV>Oracle虽然提供了DBCA的建库工具,但是有些情况下面我们也需要手工建库,下面我将对手工建库进行详细的说明<BR>(1)创建监听程序,我们使用netmgr来建立监听,比如说:你要建立的库SID为RAC1,你可以在NETMGR中添加你的监听<BR>(2)创建INITSID.ORA文件,你可以使用$ORACLE_HOME/dbs/init.ora更改,也可以通过以有的initsid.ora文件修改<BR>(3)使用orapwd建立pwdSID.ora文件<BR>orapwd file=$ORACLE_HOME/rbs/pwdSID.ora password=xxxx entries=4<BR>(4)使用conn <A href="mailto:sys/xxx@SID">sys/xxx@SID</A> as sysdba<BR>startup nomount p……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[Oracle 体系结构介绍]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=39377]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Sat, 06 Aug 2005 04:24:59 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[Oracle 体系结构介绍<p>在本章里你可以了解以下内容 <br />1、 ORACLE 实例——包括内存结构与后台进程 <br />2、 ORACLE 数据库——物理操作系统文件的集合 <br />3、 了解内存结构的组成 <br />4、 了解后台进程的作用 <br />5、 了解数据库的物理文件 <br />6、 解释各种逻辑结构 <br />一、ORACLE实例<br />1、ORACLE 实例 <br />System Global Area(SGA) 和 Background Process 称为数据库的实例。 <br />2、ORACLE 数据库 <br />一系列物理文件的集合（数据文件，控制文件，联机日志，参数文件等） <br />3、系统全局共享区System G……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[Oracle solaris 安装]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=36694]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Wed, 20 Jul 2005 02:55:30 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[Oracle 8.1.7 for solaris x86的安装<p><table cellspacing="0" cellpadding="4" width="100%" border="0"><tbody><tr><td valign="top" align="center" colspan="2"><font face="Tahoma"><font class="bigfont"><b>Oracle 8.1.7 安装文档（for Solaris 8/9）</b></font><br /></font>[ <a href="javascript:s2t()"><font color="#ff0000">繁体中文/BIG5</font></a> ] [ <a href="javascript:t2s()"><font color="#ff0000">简体中文/GB</font></a> ]</td></tr><tr><td align="center" colspan="2"><hr width="90%" size="1" bgcolor="#d9d……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[IGENUS问题解决方法]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=35858]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Fri, 15 Jul 2005 09:57:04 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[IGENUS问题的解决！<p><table cellspacing="0" cellpadding="0" width="95%" border="0"><tbody><tr><td align="center" width="100%"><h2><b>IGENUS FAQ</b></h2></td></tr><tr><td width="100%"><p>qmail + vpopmail+igenus</p><p /><p><font size="1">A.igenus不能发信----〉&nbsp;解决方法：chmod&nbsp;777&nbsp;/usr/sbin/qmail&nbsp;&nbsp;<br />&nbsp;<br />B.igenus登陆时出现错误----&gt;解决方法：编辑php.ini(如果是linux自带的php&nbsp;&nbsp;<br />应该是载/etc/php.ini)修改register_globals&nbsp;=&nbsp;On&nbsp;&nbsp;<br……  ]]></description>
		</item>	
			<item>
			<title><![CDATA[solaris 添加磁盘]]></title>
			<link><![CDATA[http://blog.chinaunix.net/u/250/showart.php?id=35528]]></link>
			<author></author>
			<guid></guid>
			<category></category>
			<pubDate>Wed, 13 Jul 2005 08:46:23 GMT</pubDate>
			<comments></comments>
			<description><![CDATA[如何在solaris中添加删除磁盘和分区<p>建意你先看 IDE 和 SCSI 分配名称 <br /><br />以下例子是格式化 Primary IDE Master 硬盘 <br /><br />查看 IDE 和 SCSI 分配名称后，我们知道 Primary IDE Master 硬盘名称是c0d0。 <br /><br />请先行 Login 成为 root user <br /><br /># drvconfig ( configure the /devices directory ) <br /># disks ( creates /dev entries for hard disks attached to the system ) <br /># format <br />Searching for disks...done <br /><br />AVAILABLE DISK SELECTIONS: <br />0. c0d0 <br />/pci@0,0……  ]]></description>
		</item>	
			</channel>
	</rss>
