<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ##shell十三問之4:""(雙引號)與''(單引號)差在哪? ------------------------------------------------ 還是回到我們的`command line`來吧... 經過前面兩章的學習,應該很清楚當你在`shell prompt`后面敲打鍵盤, 直到按下`Enter`鍵的時候,你輸入的文字就是`command line`了, 然后`shell`才會以進程的方式執行你所交給它的命令。 但是,你又可知道:你在`command line`中輸入的每一個文字, 對`shell`來說,是有類別之分的呢? 簡單而言,(我不敢說精確的定義,注1), `command line`的每一個`charactor`, 分為如下兩種: - literal:也就是普通的純文字,對`shell`來說沒特殊功能; - meta: 對`shell`來說,具有特定功能的特殊保留元字符。 > **Note:** > 對于`bash shell`在處理`comamnd line`的順序說明, > 請參考O'Reilly出版社的**Learning the Bash Shell,2nd Edition**, > 第177-180頁的說明,尤其是178頁的流程圖:Figure 7-1 ... `literal`沒什么好談的, 像abcd、123456這些"文字"都是literal...(so easy? ^_^) 但meta卻常使我們困惑...(confused?) 事實上,前兩章,我們在`command line`中已碰到兩個 似乎每次都會碰到的meta: - `IFS`:有`space`或者`tab`或者`Enter`三者之一組成(我們常用space) - `CR`: 由`Enter`產生; `IFS`是用來拆解`command line`中每一個詞(word)用的, 因為`shell command line`是按詞來處理的。 而`CR`則是用來結束`command line`用的,這也是為何我們敲`Enter`鍵, 命令就會跑的原因。 除了常用的`IFS`與`CR`, 常用的meta還有: |meta字符| meta字符作用| |--------|-------------| |= |設定變量| |$ | 作變量或運算替換(請不要與`shell prompt`混淆)|命令 |>| 輸出重定向(重定向stdout)| |<|輸入重定向(重定向stdin)| |\||命令管道| |&|重定向file descriptor或將命令至于后臺(bg)運行| |()|將其內部的命令置于nested subshell執行,或用于運算或變量替換| |{}|將期內的命令置于non-named function中執行,或用在變量替換的界定范圍| |;|在前一個命令執行結束時,而忽略其返回值,繼續執行下一個命令| |&&|在前一個命令執行結束時,若返回值為true,繼續執行下一個命令| |\|\||在前一個命令執行結束時,若返回值為false,繼續執行下一個命令| |!|執行histroy列表中的命令| |... | ...| 假如我們需要在`command line`中將這些保留元字符的功能關閉的話, 就需要quoting處理了。 在`bash`中,常用的quoting有以下三種方法: - hard quote:''(單引號),凡在hard quote中的所有meta均被關閉; - soft quote:""(雙引號),凡在soft quote中大部分meta都會被關閉,但某些會保留(如$); - escape: \ (反斜杠),只有在緊接在escape(跳脫字符)之后的單一meta才被關閉; > **Note:** > 在soft quote中被豁免的具體meta清單,我不完全知道, > 有待大家補充,或通過實踐來發現并理解。 下面的例子將有助于我們對quoting的了解: ```shell $ A=B C #空白符未被關閉,作為IFS處理 $ C:command not found. $ echo $A $ A="B C" #空白符已被關掉,僅作為空白符 $ echo $A B C ``` 在第一個給A變量賦值時,由于空白符沒有被關閉, `command line` 將被解釋為: `A=B 然后碰到<IFS>,接著執行C命令` 在第二次給A變量賦值時,由于空白符被置于soft quote中, 因此被關閉,不在作為`IFS`; `A=B<space>C` 事實上,空白符無論在soft quote還是在hard quote中, 均被關閉。Enter鍵字符亦然: ```shell $ A=`B > C > ' $ echo "$A" B C ``` 在上例中,由于`enter`被置于hard quote當中,因此不再作為`CR`字符來處理。 這里的`enter`單純只是一個斷行符號(new-line)而已, 由于`command line`并沒得到`CR`字符, 因此進入第二個`shell prompt`(`PS2`, 以>符號表示), `command line`并不會結束,直到第三行, 我們輸入的`enter`并不在hard quote里面, 因此沒有被關閉, 此時,`command line`碰到`CR`字符,于是結束,交給shell來處理。 上例的`Enter`要是被置于soft quote中的話,`CR`字符也會同樣被關閉: ```shell $ A="B > C > " $ echo $A B C ``` 然而,由于 `echo $A`時的變量沒有置于soft quote中, 因此,當變量替換完成后,并作命令行重組時,`enter`被解釋為`IFS`, 而不是new-line字符。 同樣的,用escape亦可關閉CR字符: ```shell $ A=B\ > C\ > $ echo $A BC ``` 上例中的,第一個`enter`跟第二個`enter`均被escape字符關閉了, 因此也不作為`CR`來處理,但第三個`enter`由于沒有被escape, 因此,作為`CR`結束`command line`。 但由于`enter`鍵本身在shell meta中特殊性,在 \ escape字符后面 僅僅取消其`CR`功能, 而不保留其IFS功能。 你或許發現光是一個`enter`鍵所產生的字符,就有可能是如下這些可能: - CR - IFS - NL(New Line) - FF(Form Feed) - NULL - ... 至于,什么時候解釋為什么字符,這個我就沒法去挖掘了, 或者留給讀者君自行慢慢摸索了...^-^ 至于soft quote跟hard quote的不同,主要是對于某些meta的關閉與否,以$來做說明: ```shell $ A=B\ C $ echo "$A" B C $ echo '$A' $A ``` 在第一個`echo`命令行中,$被置于soft quote中,將不被關閉, 因此繼續處理變量替換, 因此,`echo`將A的變量值輸出到屏幕,也就是"B C"的結果。 在第二個`echo`命令行中,$被置于hard quote中,則被關閉, 因此,$只是一個$符號,并不會用來做變量替換處理, 因此結果是$符號后面接一個A字母:$A. > **練習與思考:** 如下結果為何不同? > tips: 單引號和雙引號,在quoting中均被關閉了。 ```shell $ A=B\ C $ echo '"$A"' #最外面的是單引號 "$A" $ echo "'$A'" #最外面的是雙引號 'B C' ``` ------------------------------------ 在CU的shell版里,我發現很多初學者的問題, 都與quoting的理解有關。 比方說,若我們在awk或sed的命令參數中, 調用之前設定的一些變量時,常會問及為何不能的問題。 要解決這些問題,關鍵點就是:**區分出 shell meta 與 command meta** 前面我們提到的那些meta,都是在command line中有特殊用途的, 比方說{}就是將一系列的command line置于不具名的函數中執行(可簡單視為command block), 但是,awk卻需要用{}來區分出awk的命令區段(BEGIN,MAIN,END). 若你在command line中如此輸入: ```shell $ awk {print $0} 1.txt ``` 由于{}在shell中并沒有關閉,那shell就將{print $0}視為command block, 但同時沒有`;`符號作命令分隔,因此,就出現awk語法錯誤結果。 要解決之,可用hard quote: ```shell awk '{print $0}' ``` 上面的hard quote應好理解,就是將原來的 {、<space>、$、}這幾個shell meta關閉, 避免掉在shell中遭到處理,而完整的成為awk的參數中command meta。 > **Note:** > awk中使用的$0 是awk中內建的field nubmer,而非awk的變量, > awk自身的變量無需使用$. 要是理解了hard quote的功能,在來理解soft quote與escape就不難: ```shell awk "{print \$0}" 1.txt awk \{print \$0\} 1.txt ``` 然而,若要你改變awk的$0的0值是從另一個shell變量中讀進呢? 比方說:已有變量$A的值是0, 那如何在`command line`中解決 awk的$$A呢? 你可以很直接否定掉hard quote的方案: ```shell $ awk '{print $$A}' 1.txt ``` 那是因為$A的$在hard quote中是不能替換變量的。 聰明的讀者(如你!),經過本章的學習,我想,你應該可以理解為 為何我們可以使用如下操作了吧: ```shell A=0 awk "{print \$$A}" 1.txt awk \{print\ \$$A\} 1.txt awk '{print $'$A'}' 1.txt awk '{print $'"$A"'}' 1.txt ``` 或許,你能給出更多方案... ^_^ 更多練習: - http://bbs.chinaunix.net/forum/viewtopic.php?t=207178 一個關于read命令的小問題: 很早以前覺得很奇怪:執行read命令,然后讀取用戶輸入給變量賦值, 但如果輸入是以空格鍵開始的話,這空格會被忽略,比如: ```shell read a #輸入: abc echo "$a" #只輸出abc ``` 原因: 變量a的值,從終端輸入的值是以IFS開頭,而這些IFS將被shell解釋器忽略(trim)。 應該與shell解釋器分詞的規則有關; ```shell read a #輸入:\ \ \ abc echo "$a" #只輸出abc ``` 需要將空格字符轉義 > **Note:** > IFS Internal field separators, normally space, tab, and newline (see Blank Interpretation section). > ...... > Blank Interpretation > After parameter and command substitution, the results of substitution > are scanned for internal field separator characters (those found in IFS) > and split into distinct arguments where such characters are found. > Explicit null arguments ("" or '') are retained. > Implicit null arguments(those resulting from parameters that have no values) > are removed. > (refre to: man sh) 解決思路: 1. shell command line 主要是將整行line給分解(break down)為每一個單詞(word); 2. 而詞與詞之間的分隔符就是IFS (Internal Field Seperator)。 3. shell會對command line作處理(如替換,quoting等), 然后再按詞重組。(注:別忘了這個重組特性) 4. 當你用IFS來事開頭一個變量值,那shell會先整理出這個詞,然后在重組command line。 5.然而,你將IFS換成其他,那shell將視你哪些space/tab為“詞”,而不是IFS。那在重組時,可以得到這些詞。 若你還是不理解,那來驗證一下下面這個例子: ```shell $ A=" abc" $ echo $A abc $ echo "$A" #note1 abc $ old_IFS=$IFS $ IFS=; $ echo $A abc $ IFS=$old_IFS $ echo $A abc ``` > **Note:** > 1. 這里是用 soft quoting 將里面的 space 關閉,使之不是 meta(IFS), > 而是一個literal(white space); > 2. IFS=; 意義是將IFS設置為空字符,因為;是shell的元字符(meta); 問題二:為什么多做了幾個分號,我想知道為什么會出現空格呢? ```shell $ a=";;;test" $ IFS=";" $ echo $a test $ a=" test" $ echo $a test $ IFS=" " $ echo $a test ``` 解答: 這個問題,出在`IFS=;`上。 因為這個`;`在問題一中的command line上是一個meta, 并非`";"`符號本身。 因此,`IFS=;`是將IFS設置為 null charactor (不是space、tab、newline)。 要不是試試下面這個代碼片段: ```shell $ old_IFS=$IFS $ read A ;a;b;c $ echo $A ;a;b;c $ IFS=";" #Note2 $ echo $A a b c ``` > **Note:** > 要關閉`;`可用`";"`或者`';'`或者`\;`。 - http://bbs.chinaunix.net/forum/viewtopic.php?t=216729 思考問題二:文本處理:讀文件時,如何保證原汁原味。 ```shell cat file | while read i do echo $i done ``` 文件file的行中包含若干空,經過read只保留不重復的空格。 如何才能所見即所得。 ```shell cat file | while read i do echo "X${i}X" done ``` 從上面的輸出,可以看出read,讀入是按整行讀入的; 不能原汁原味的原因: 1. 如果行的起始部分有IFS之類的字符,將被忽略; 2. `echo $i`的解析過程中,首先將$i替換為字符串, 然后對echo 字符串中字符串分詞,然后命令重組,輸出結果; 在分詞,與命令重組時,可能導致多個相鄰的IFS轉化為一個; ```shell cat file | while read i do echo "$i" done ``` 以上代碼可以解決原因2中的,command line的分詞和重組導致meta字符丟失; 但仍然解決不了原因1中,read讀取行時,忽略行起始的IFS meta字符。 回過頭來看上面這個問題:為何要原汁原味呢? cat命令就是原汁原味的,只是shell的read、echo導致了某些shell的meta字符丟失; 如果只是IFS meta的丟失,可以采用如下方式: 將IFS設置為null,即`IFS=;`, 在此再次重申此處`;`是shell的meta字符,而不是literal字符; 因此要使用literal的 `;`應該是`\;` 或者關閉meta 的(soft/hard) quoting的`";"`或者`';'`。 因此上述的解決方案是: ```shell old_IFS=$IFS IFS=; #將IFS設置為null cat file | while read i do echo "$i" done IFS=old_IFS #恢復IFS的原始值 ``` 現在,回過頭來看這個問題,為什么會有這個問題呢; 其本源的問題應該是沒有找到解決原始問題的最合適的方法, 而是采取了一個迂回的方式來解決了問題; 因此,我們應該回到問題的本源,重新審視一下,問題的本質。 如果要精準的獲取文件的內容,應該使用od或者hexdump會更好些。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看