<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>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                在這一章我們將看一下,當你按下 enter 鍵后,發生在命令行中的一些“魔法”。雖然我們會 仔細查看幾個復雜有趣的 shell 特點,但我們只使用一個新命令來處理這些特性。 > * echo - 顯示一行文本 ## (字符)展開 每一次你輸入一個命令,然后按下 enter 鍵,在 bash 執行你的命令之前,bash 會對輸入 的字符完成幾個步驟處理。我們已經知道兩三個案例,怎樣一個簡單的字符序列,例如“`*`”, 對 shell 來說,有很多的涵義。使這個發生的過程叫做(字符)展開。通過展開, 你輸入的字符,在 shell 對它起作用之前,會展開成為別的字符。為了說明我們所要 表達的意思,讓我們看一看 echo 命令。echo 是一個 shell 內部命令,來完成非常簡單的任務。 它在標準輸出中打印出它的文本參數。 ~~~ [me@linuxbox ~]$ echo this is a test this is a test ~~~ 這個命令的作用相當簡單明了。傳遞到 echo 命令的任一個參數都會在(屏幕上)顯示出來。 讓我們試試另一個例子: ~~~ [me@linuxbox ~]$ echo * Desktop Documents ls-output.txt Music Pictures Public Templates Videos ~~~ 那么剛才發生了什么事情呢? 為什么 echo 不打印“`*`”呢?隨著你回想起我們所學過的 關于通配符的內容,這個“`*`”字符意味著匹配文件名中的任意字符,但是在原先的討論 中我們卻不知道 shell 是怎樣實現這個功能的。最簡單的答案就是 shell 把“`*`”展開成了 另外的東西(在這種情況下,就是在當前工作目錄下的文件名字),在 echo 命令被執行 前。當回車鍵被按下時,shell 在命令被執行前在命令行上自動展開任何符合條件的字符, 所以 echo 命令從不會發現“`*`”,只把它展開成結果。知道了這個以后,我們能看到 echo 執行 的結果和我們想象的一樣。 ## 路徑名展開 這種通配符工作機制叫做路徑名展開。如果我們試一下在之前的章節中使用的技巧, 我們會看到它們真是要展開的字符。給出一個家目錄,它看起來像這樣: ~~~ [me@linuxbox ~]$ ls Desktop ls-output.txt Pictures Templates .... ~~~ 我們能夠執行以下參數展開模式: ~~~ [me@linuxbox ~]$ echo D* Desktop Documents ~~~ 和: ~~~ [me@linuxbox ~]$ echo *s Documents Pictures Templates Videos ~~~ 甚至是: ~~~ [me@linuxbox ~]$ echo [[:upper:]]* Desktop Documents Music Pictures Public Templates Videos ~~~ 查看家目錄之外的目錄: ~~~ [me@linuxbox ~]$ echo /usr/*/share /usr/kerberos/share /usr/local/share ~~~ > 隱藏文件路徑名展開 > > 正如我們知道的,以圓點字符開頭的文件名是隱藏文件。路徑名展開也尊重這種 行為。像這樣的展開: > > echo * > > 不會顯示隱藏文件 > > 要是展開模式以一個圓點開頭,我們就能夠在展開模式中包含隱藏文件, 而且隱藏文件可能會出現在第一位置,就像這樣: > > echo .* > > 它幾乎是起作用了。然而,如果我們仔細檢查一下輸出結果,我們會看到名字”.” 和”..”也出現在結果中。因為這些名字是指當前工作目錄和它的父目錄,使用這種 模式可能會產生不正確的結果。我們能看到這樣的結果,如果我們試一下這個命令: > > ls -d .* | less > > 為了在這種情況下正確地完成路徑名展開,我們應該雇傭一個更精確些的模式。 這個模式會正確地工作: > > ls -d .[!.]?* > > 這種模式展開成為文件名,每個文件名以圓點開頭,第二個字符不包含圓點,再包含至少一個字符, 并且這個字符之后緊接著任意多個字符。這將列出大多數的隱藏文件 (但仍將不能包含以多個圓點開頭的文件名)這個帶有 -A 選項(“幾乎所有”)的 ls 命令能夠提供一份正確的隱藏文件清單: > > ls -A ## 波浪線展開 可能你從我們對 cd 命令的介紹中回想起來,波浪線字符(“`~`”)有特殊的意思。當它用在 一個單詞的開頭時,它會展開成指定用戶的家目錄名,如果沒有指定用戶名,則是當前用戶的家目錄: ~~~ [me@linuxbox ~]$ echo ~ /home/me ~~~ 如果有用戶”foo”這個帳號,然后: ~~~ [me@linuxbox ~]$ echo ~foo /home/foo ~~~ ## 算術表達式展開 shell 允許算術表達式通過展開來執行。這允許我們把 shell 提示當作計算器來使用: ~~~ [me@linuxbox ~]$ echo $((2 + 2)) 4 ~~~ 算術表達式展開使用這種格式: ~~~ $((expression)) ~~~ (以上括號中的)表達式是指算術表達式,它由數值和算術操作符組成。 算術表達式只支持整數(全部是數字,不帶小數點),但是能執行很多不同的操作。這里是 一些它支持的操作符: 表 8-1: 算術操作符 | 操作符 | 說明 | |--------|-------| | + | 加 | | - | 減 | | * | 乘 | | / | 除(但是記住,因為展開只是支持整數除法,所以結果是整數。) | | % | 取余,只是簡單的意味著,“余數” | | ** | 取冪 | 在算術表達式中空格并不重要,并且表達式可以嵌套。例如,5的平方乘以3: ~~~ [me@linuxbox ~]$ echo $(($((5**2)) * 3)) 75 ~~~ 一對括號可以用來把多個子表達式括起來。通過這個技術,我們可以重寫上面的例子, 同時用一個展開代替兩個,來得到一樣的結果: ~~~ [me@linuxbox ~]$ echo $(((5**2) * 3)) 75 ~~~ 這是一個使用除法和取余操作符的例子。注意整數除法的結果: ~~~ [me@linuxbox ~]$ echo Five divided by two equals $((5/2)) Five divided by two equals 2 [me@linuxbox ~]$ echo with $((5%2)) left over. with 1 left over. ~~~ 在35章會更深入的討論算術表達式的內容。 ## 花括號展開 可能最奇怪的展開是花括號展開。通過它,你可以從一個包含花括號的模式中 創建多個文本字符串。這是一個例子: ~~~ [me@linuxbox ~]$ echo Front-{A,B,C}-Back Front-A-Back Front-B-Back Front-C-Back ~~~ 花括號展開模式可能包含一個開頭部分叫做報頭,一個結尾部分叫做附言。花括號表達式本身可 能包含一個由逗號分開的字符串列表,或者一系列整數,或者單個的字符串。這種模式不能 嵌入空白字符。這個例題使用了一系列整數: ~~~ [me@linuxbox ~]$ echo Number_{1..5} Number_1 Number_2 Number_3 Number_4 Number_5 ~~~ 一系列以倒序排列的字母: ~~~ [me@linuxbox ~]$ echo {Z..A} Z Y X W V U T S R Q P O N M L K J I H G F E D C B A ~~~ 花括號展開可以嵌套: ~~~ [me@linuxbox ~]$ echo a{A{1,2},B{3,4}}b aA1b aA2b aB3b aB4b ~~~ 那么這對什么有好處呢?最普遍的應用是,創建一系列的文件或目錄列表。例如, 如果我們是攝影師,有大量的相片。我們想把這些相片按年月先后組織起來。首先, 我們要創建一系列以數值”年-月”形式命名的目錄。通過這種方式,目錄名按照 年代順序排列。我們可以鍵入整個目錄列表,但是工作量太大了,并且易于出錯。 反而,我們可以這樣做: ~~~ [me@linuxbox ~]$ mkdir Pics [me@linuxbox ~]$ cd Pics [me@linuxbox Pics]$ mkdir {2007..2009}-0{1..9} {2007..2009}-{10..12} [me@linuxbox Pics]$ ls 2007-01 2007-07 2008-01 2008-07 2009-01 2009-07 2007-02 2007-08 2008-02 2008-08 2009-02 2009-08 2007-03 2007-09 2008-03 2008-09 2009-03 2009-09 2007-04 2007-10 2008-04 2008-10 2009-04 2009-10 2007-05 2007-11 2008-05 2008-11 2009-05 2009-11 2007-06 2007-12 2008-06 2008-12 2009-06 2009-12 ~~~ 棒極了! ## 參數展開 在這一章我們將會簡單地介紹參數展開,只是皮毛而已。后續章節我們會廣泛地 討論參數展開。這個特性在 shell 腳本中比直接在命令行中更有用。它的許多性能 和系統存儲小塊數據,并給每塊數據命名的能力有關系。許多像這樣的小塊數據, 更適當些應叫做變量,可以方便地檢查它們。例如,叫做”USER”的變量包含你的 用戶名。喚醒參數展開,揭示 USER 中的內容,可以這樣做: ~~~ [me@linuxbox ~]$ echo $USER me ~~~ 查看有效的變量列表,試試這個: ~~~ [me@linuxbox ~]$ printenv | less ~~~ 你可能注意到其它展開類型,如果你誤輸入一個模式,展開就不會發生。這時 echo 命令只簡單地顯示誤鍵入的模式。通過參數展開,如果你拼寫錯了一個變量名, 展開仍然會進行,只是展成一個空字符串: ~~~ [me@linuxbox ~]$ echo $SUER [me@linuxbox ~]$ ~~~ ## 命令替換 命令替換允許我們把一個命令的輸出作為一個展開模式來使用: ~~~ [me@linuxbox ~]$ echo $(ls) Desktop Documents ls-output.txt Music Pictures Public Templates Videos ~~~ 我最喜歡用的一行命令是像這樣的: ~~~ [me@linuxbox ~]$ ls -l $(which cp) -rwxr-xr-x 1 root root 71516 2007-12-05 08:58 /bin/cp ~~~ 這里我們把 which cp 的執行結果作為一個參數傳遞給 ls 命令,因此要想得到 cp 程序的 輸出列表,不必知道它完整的路徑名。我們不只限制于簡單命令。也可以使用整個管道線 (只展示部分輸出): ~~~ [me@linuxbox ~]$ file $(ls /usr/bin/* | grep zip) /usr/bin/bunzip2: symbolic link to `bzip2' .... ~~~ 在這個例子中,管道線的輸出結果成為 file 命令的參數列表。 在舊版 shell 程序中,有另一種語法也支持命令替換,可與剛提到的語***換使用。 bash 也支持這種語法。它使用倒引號來代替美元符號和括號: ~~~ [me@linuxbox ~]$ ls -l `which cp` -rwxr-xr-x 1 root root 71516 2007-12-05 08:58 /bin/cp ~~~ ## 引用 我們已經知道 shell 有許多方式可以完成展開,現在是時候學習怎樣來控制展開了。 以下面例子來說明: ~~~ [me@linuxbox ~]$ echo this is a test this is a test ~~~ 或者: ~~~ [me@linuxbox ~]$ echo The total is $100.00 The total is 00.00 ~~~ 在第一個例子中,shell 從 echo 命令的參數列表中,刪除多余的空格。在第二個例子中, 參數展開把?`$1`?的值替換為一個空字符串,因為?`1`?是沒有定義的變量。shell 提供了一種 叫做引用的機制,來有選擇地禁止不需要的展開。 ## 雙引號 我們將要看一下引用的第一種類型,雙引號。如果你把文本放在雙引號中, shell 使用的特殊字符,除了 `$`,`\` (反斜杠),和 \`(倒引號)之外, 則失去它們的特殊含義,被當作普通字符來看待。這意味著單詞分割,路徑名展開, 波浪線展開,和花括號展開都被禁止,然而參數展開,算術展開,和命令替換 仍然執行。使用雙引號,我們可以處理包含空格的文件名。比方說我們是不幸的 名為?two words.txt?文件的受害者。如果我們試圖在命令行中使用這個 文件,單詞分割機制會導致這個文件名被看作兩個獨自的參數,而不是所期望 的單個參數: ~~~ [me@linuxbox ~]$ ls -l two words.txt ls: cannot access two: No such file or directory ls: cannot access words.txt: No such file or directory ~~~ 使用雙引號,我們可以阻止單詞分割,得到期望的結果;進一步,我們甚至可以修復 破損的文件名。 ~~~ [me@linuxbox ~]$ ls -l "two words.txt" -rw-rw-r-- 1 me me 18 2008-02-20 13:03 two words.txt [me@linuxbox ~]$ mv "two words.txt" two_words.txt ~~~ 你瞧!現在我們不必一直輸入那些討厭的雙引號了。 記住,在雙引號中,參數展開,算術表達式展開,和命令替換仍然有效: ~~~ [me@linuxbox ~]$ echo "$USER $((2+2)) $(cal)" me 4 February 2008 Su Mo Tu We Th Fr Sa .... ~~~ 我們應該花費一點時間來看一下雙引號在命令替換中的效果。首先仔細研究一下單詞分割 是怎樣工作的。在之前的范例中,我們已經看到單詞分割機制是怎樣來刪除文本中額外空格的: ~~~ [me@linuxbox ~]$ echo this is a test this is a test ~~~ 在默認情況下,單詞分割機制會在單詞中尋找空格,制表符,和換行符,并把它們看作 單詞之間的界定符。它們只作為分隔符使用。因為它們把單詞分為不同的參數,在范例中, 命令行包含一個帶有四個不同參數的命令。如果我們加上雙引號: ~~~ [me@linuxbox ~]$ echo "this is a test" this is a test ~~~ 單詞分割被禁止,內嵌的空格也不會被當作界定符,它們成為參數的一部分。 一旦加上雙引號,我們的命令行就包含一個帶有一個參數的命令。 事實上,單詞分割機制把換行符看作界定符,對命令替換產生了一個,雖然微妙,但有趣的影響。 考慮下面的例子: ~~~ [me@linuxbox ~]$ echo $(cal) February 2008 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 [me@linuxbox ~]$ echo "$(cal)" February 2008 .... ~~~ 在第一個實例中,沒有引用的命令替換導致命令行包含38個參數。在第二個例子中, 命令行只有一個參數,參數中包括嵌入的空格和換行符。 ## 單引號 如果需要禁止所有的展開,我們使用單引號。以下例子是無引用,雙引號,和單引號的比較結果: ~~~ [me@linuxbox ~]$ echo text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER text /home/me/ls-output.txt a b foo 4 me [me@linuxbox ~]$ echo "text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER" text ~/*.txt {a,b} foo 4 me [me@linuxbox ~]$ echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER' text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER ~~~ 正如我們所看到的,隨著引用程度加強,越來越多的展開被禁止。 ## 轉義字符 有時候我們只想引用單個字符。我們可以在字符之前加上一個反斜杠,在這個上下文中叫做轉義字符。 經常在雙引號中使用轉義字符,來有選擇地阻止展開。 ~~~ [me@linuxbox ~]$ echo "The balance for user $USER is: \$5.00" The balance for user me is: $5.00 ~~~ 使用轉義字符來消除文件名中一個字符的特殊含義,是很普遍的。例如,在文件名中可能使用 一些對于 shell 來說,有特殊含義的字符。這些字符包括”$”, “!”, “ “等字符。在文件名 中包含特殊字符,你可以這樣做: ~~~ [me@linuxbox ~]$ mv bad\&filename good_filename ~~~ 為了允許反斜杠字符出現,輸入”\“來轉義。注意在單引號中,反斜杠失去它的特殊含義,它 被看作普通字符。 > 反斜杠轉義字符序列 > > 反斜杠除了作為轉義字符外,反斜杠也是一種表示法的一部分,這種表示法代表某種 特殊字符,叫做控制碼。ASCII 編碼表中前32個字符被用來把命令轉輸到像電報機 一樣的設備。一些編碼是眾所周知的(制表符,退格符,換行符,和回車符),其它 一些編碼就不熟悉了(空值,傳輸結束碼,和確認)。 > > | 轉義序列 | 含義 | > | \a | 響鈴(”警告”-導致計算機嘟嘟響) | > | \b | 退格符 | > | \n | 新的一行。在類 Unix 系統中,產生換行。 | > | \r | 回車符 | > | \t | 制表符 | > > 上表列出了一些常見的反斜杠轉義字符。反斜杠表示法背后的思想來源于 C 編程語言, 許多其它語言也采用了這種表示方法,包括 shell。 > > echo 命令帶上 ‘-e’ 選項,能夠解釋轉義序列。你可以把轉義序列放在 $' ' 里面。 以下例子,使用 sleep 命令,一個簡單的程序,它會等待指定的秒數,然后退出。 我們可以創建一個簡單的倒數計數器: > > sleep 10; echo -e "Time's up\a" > > 我們也可以這樣做: > > sleep 10; echo "Time's up" /span>\a' ## 總結歸納 隨著我們繼續學習 shell,你會發現使用展開和引用的頻率逐漸多起來,所以能夠很好的 理解他們的工作方式很有意義。事實上,可以這樣說,他們是學習 shell 的最重要的主題。 如果沒有準確地理解展開模式,shell 總是神秘和混亂的源泉,并且 shell 潛在的能力也 浪費掉了。 ## 拓展閱讀 * Bash 手冊頁有主要段落是關于展開和引用的,它們以更正式的方式介紹了這些題目。 * Bash 參考手冊也包含章節,介紹展開和引用: [http://www.gnu.org/software/bash/manual/bashref.html](http://www.gnu.org/software/bash/manual/bashref.html)
                  <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>

                              哎呀哎呀视频在线观看