<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、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## 10.5 數據流重導向 數據流重導向 (redirect) 由字面上的意思來看,好像就是將“數據給他傳導到其他地方去”的樣子? 沒錯~數據流重導向就是將某個指令執行后應該要出現在屏幕上的數據, 給他傳輸到其他的地方,例如文件或者是設備 (例如打印機之類的)!這玩意兒在 Linux 的文字模式下面可重要的! 尤其是如果我們想要將某些數據儲存下來時,就更有用了! ### 10.5.1 什么是數據流重導向 什么是數據流重導向啊?這得要由指令的執行結果談起!一般來說,如果你要執行一個指令,通常他會是這樣的: ![指令執行過程的數據傳輸情況](https://box.kancloud.cn/2016-05-13_573573777320c.jpg)圖10.5.1、指令執行過程的數據傳輸情況 我們執行一個指令的時候,這個指令可能會由文件讀入數據,經過處理之后,再將數據輸出到屏幕上。 在上圖當中, standard output 與 standard error output 分別代表“標準輸出 (STDOUT)”與“標準錯誤輸出 (STDERR)”, 這兩個玩意兒默認都是輸出到屏幕上面來的啊!那么什么是標準輸出與標準錯誤輸出呢? * standard output 與 standard error output 簡單的說,標準輸出指的是“指令執行所回傳的正確的訊息”,而標準錯誤輸出可理解為“ 指令執行失敗后,所回傳的錯誤訊息”。舉個簡單例子來說,我們的系統默認有 /etc/crontab 但卻無 /etc/vbirdsay, 此時若下達“ cat /etc/crontab /etc/vbirdsay ”這個指令時,cat 會進行: * 標準輸出:讀取 /etc/crontab 后,將該文件內容顯示到屏幕上; * 標準錯誤輸出:因為無法找到 /etc/vbirdsay,因此在屏幕上顯示錯誤訊息 不管正確或錯誤的數據都是默認輸出到屏幕上,所以屏幕當然是亂亂的!那能不能通過某些機制將這兩股數據分開呢? 當然可以啊!那就是數據流重導向的功能啊!數據流重導向可以將 standard output (簡稱 stdout) 與 standard error output (簡稱 stderr) 分別傳送到其他的文件或設備去,而分別傳送所用的特殊字符則如下所示: 1. 標準輸入  (stdin) :代碼為 0 ,使用 &lt; 或 &lt;&lt; ; 2. 標準輸出  (stdout):代碼為 1 ,使用 &gt; 或 &gt;&gt; ; 3. 標準錯誤輸出(stderr):代碼為 2 ,使用 2&gt; 或 2&gt;&gt; ; 為了理解 stdout 與 stderr ,我們先來進行一個范例的練習: ``` 范例一:觀察你的系統根目錄 (/) 下各目錄的文件名、權限與屬性,并記錄下來 [dmtsai@study ~]$ ll / &lt;==此時屏幕會顯示出文件名信息 [dmtsai@study ~]$ ll / &gt; ~/rootfile &lt;==屏幕并無任何信息 [dmtsai@study ~]$ ll ~/rootfile &lt;==有個新文件被創建了! -rw-rw-r--. 1 dmtsai dmtsai 1078 Jul 9 18:51 /home/dmtsai/rootfile ``` 怪了!屏幕怎么會完全沒有數據呢?這是因為原本“ ll / ”所顯示的數據已經被重新導向到 ~/rootfile 文件中了! 那個 ~/rootfile 的文件名可以隨便你取。如果你下達“ cat ~/rootfile ”那就可以看到原本應該在屏幕上面的數據啰。 如果我再次下達:“ ll /home &gt; ~/rootfile ”后,那個 ~/rootfile 文件的內容變成什么? 他將變成“僅有 ll /home 的數據”而已!咦!原本的“ ll / ”數據就不見了嗎?是的!因為該文件的創建方式是: 1. 該文件 (本例中是 ~/rootfile) 若不存在,系統會自動的將他創建起來,但是 2. 當這個文件存在的時候,那么系統就會先將這個文件內容清空,然后再將數據寫入! 3. 也就是若以 &gt; 輸出到一個已存在的文件中,那個文件就會被覆蓋掉啰! 那如果我想要將數據累加而不想要將舊的數據刪除,那該如何是好?利用兩個大于的符號 (&gt;&gt;) 就好啦!以上面的范例來說,你應該要改成“ ll / &gt;&gt; ~/rootfile ”即可。 如此一來,當 (1) ~/rootfile 不存在時系統會主動創建這個文件;(2)若該文件已存在, 則數據會在該文件的最下方累加進去! 上面談到的是 standard output 的正確數據,那如果是 standard error output 的錯誤數據呢?那就通過 2&gt; 及 2&gt;&gt; 啰!同樣是覆蓋 (2&gt;) 與累加 (2&gt;&gt;) 的特性!我們在剛剛才談到 stdout 代碼是 1 而 stderr 代碼是 2 , 所以這個 2&gt; 是很容易理解的,而如果僅存在 &gt; 時,則代表默認的代碼 1 啰!也就是說: * 1&gt; :以覆蓋的方法將“正確的數據”輸出到指定的文件或設備上; * 1&gt;&gt;:以累加的方法將“正確的數據”輸出到指定的文件或設備上; * 2&gt; :以覆蓋的方法將“錯誤的數據”輸出到指定的文件或設備上; * 2&gt;&gt;:以累加的方法將“錯誤的數據”輸出到指定的文件或設備上; 要注意喔,“ 1&gt;&gt; ”以及“ 2&gt;&gt; ”中間是沒有空格的!OK!有些概念之后讓我們繼續聊一聊這家伙怎么應用吧! 當你以一般身份執行 [find](../Text/index.html#find) 這個指令的時候,由于權限的問題可能會產生一些錯誤信息。例如執行“ find / -name testing ”時,可能會產生類似“ find: /root: Permission denied ”之類的訊息。 例如下面這個范例: ``` 范例二:利用一般身份帳號搜尋 /home 下面是否有名為 .bashrc 的文件存在 [dmtsai@study ~]$ find /home -name .bashrc &lt;==身份是 dmtsai 喔! find: '/home/arod': Permission denied &lt;== Standard error output find: '/home/alex': Permission denied &lt;== Standard error output /home/dmtsai/.bashrc &lt;== Standard output ``` 由于 /home 下面還有我們之前創建的帳號存在,那些帳號的主文件夾你當然不能進入啊!所以就會有錯誤及正確數據了。 好了,那么假如我想要將數據輸出到 list 這個文件中呢?執行“ find /home -name .bashrc &gt; list ” 會有什么結果?呵呵,你會發現 list 里面存了剛剛那個“正確”的輸出數據, 至于屏幕上還是會有錯誤的訊息出現呢!傷腦筋!如果想要將正確的與錯誤的數據分別存入不同的文件中需要怎么做? ``` 范例三:承范例二,將 stdout 與 stderr 分存到不同的文件去 [dmtsai@study ~]$ find /home -name .bashrc &gt; list_right 2&gt; list_error ``` 注意喔,此時“屏幕上不會出現任何訊息”!因為剛剛執行的結果中,有 Permission 的那幾行錯誤信息都會跑到 list_error 這個文件中,至于正確的輸出數據則會存到 list_right 這個文件中啰!這樣可以了解了嗎? 如果有點混亂的話,去休息一下再回來看看吧! * /dev/null 垃圾桶黑洞設備與特殊寫法 想像一下,如果我知道錯誤訊息會發生,所以要將錯誤訊息忽略掉而不顯示或儲存呢? 這個時候黑洞設備 /dev/null 就很重要了!這個 /dev/null 可以吃掉任何導向這個設備的信息喔!將上述的范例修訂一下: ``` 范例四:承范例三,將錯誤的數據丟棄,屏幕上顯示正確的數據 [dmtsai@study ~]$ find /home -name .bashrc 2&gt; /dev/null /home/dmtsai/.bashrc &lt;==只有 stdout 會顯示到屏幕上, stderr 被丟棄了 ``` 再想像一下,如果我要將正確與錯誤數據通通寫入同一個文件去呢?這個時候就得要使用特殊的寫法了! 我們同樣用下面的案例來說明: ``` 范例五:將指令的數據全部寫入名為 list 的文件中 [dmtsai@study ~]$ find /home -name .bashrc &gt; list 2&gt; list &lt;==錯誤 [dmtsai@study ~]$ find /home -name .bashrc &gt; list 2&gt;&1 &lt;==正確 [dmtsai@study ~]$ find /home -name .bashrc &&gt; list &lt;==正確 ``` 上述表格第一行錯誤的原因是,由于兩股數據同時寫入一個文件,又沒有使用特殊的語法, 此時兩股數據可能會交叉寫入該文件內,造成次序的錯亂。所以雖然最終 list 文件還是會產生,但是里面的數據排列就會怪怪的,而不是原本屏幕上的輸出排序。 至于寫入同一個文件的特殊語法如上表所示,你可以使用 2&gt;&1 也可以使用 &&gt; ! 一般來說,鳥哥比較習慣使用 2&gt;&1 的語法啦! * standard input : &lt; 與 &lt;&lt; 了解了 stderr 與 stdout 后,那么那個 &lt; 又是什么呀?呵呵!以最簡單的說法來說, 那就是“將原本需要由鍵盤輸入的數據,改由文件內容來取代”的意思。 我們先由下面的 cat 指令操作來了解一下什么叫做“鍵盤輸入”吧! ``` 范例六:利用 cat 指令來創建一個文件的簡單流程 [dmtsai@study ~]$ cat &gt; catfile testing cat file test &lt;==這里按下 [ctrl]+d 來離開 [dmtsai@study ~]$ cat catfile testing cat file test ``` 由于加入 &gt; 在 cat 后,所以那個 catfile 會被主動的創建,而內容就是剛剛鍵盤上面輸入的那兩行數據了。 唔!那我能不能用純文本文件取代鍵盤的輸入,也就是說,用某個文件的內容來取代鍵盤的敲擊呢? 可以的!如下所示: ``` 范例七:用 stdin 取代鍵盤的輸入以創建新文件的簡單流程 [dmtsai@study ~]$ cat &gt; catfile &lt; ~/.bashrc [dmtsai@study ~]$ ll catfile ~/.bashrc -rw-r--r--. 1 dmtsai dmtsai 231 Mar 6 06:06 /home/dmtsai/.bashrc -rw-rw-r--. 1 dmtsai dmtsai 231 Jul 9 18:58 catfile # 注意看,這兩個文件的大小會一模一樣!幾乎像是使用 cp 來復制一般! ``` 這東西非常的有幫助!尤其是用在類似 mail 這種指令的使用上。 理解 &lt; 之后,再來則是怪可怕一把的 &lt;&lt; 這個連續兩個小于的符號了。 他代表的是“結束的輸入字符”的意思!舉例來講:“我要用 cat 直接將輸入的訊息輸出到 catfile 中, 且當由鍵盤輸入 eof 時,該次輸入就結束”,那我可以這樣做: ``` [dmtsai@study ~]$ cat &gt; catfile &lt;&lt; "eof" &gt; This is a test. &gt; OK now stop &gt; eof &lt;==輸入這關鍵字,立刻就結束而不需要輸入 [ctrl]+d [dmtsai@study ~]$ cat catfile This is a test. OK now stop &lt;==只有這兩行,不會存在關鍵字那一行! ``` 看到了嗎?利用 &lt;&lt; 右側的控制字符,我們可以終止一次輸入, 而不必輸入 [crtl]+d 來結束哩!這對程序寫作很有幫助喔!好了,那么為何要使用命令輸出重導向呢?我們來說一說吧! * 屏幕輸出的信息很重要,而且我們需要將他存下來的時候; * 背景執行中的程序,不希望他干擾屏幕正常的輸出結果時; * 一些系統的例行命令 (例如寫在 /etc/crontab 中的文件) 的執行結果,希望他可以存下來時; * 一些執行命令的可能已知錯誤訊息時,想以“ 2&gt; /dev/null ”將他丟掉時; * 錯誤訊息與正確訊息需要分別輸出時。 當然還有很多的功能的,最簡單的就是網友們常常問到的:“為何我的 root 都會收到系統 crontab 寄來的錯誤訊息呢”這個咚咚是常見的錯誤, 而如果我們已經知道這個錯誤訊息是可以忽略的時候,嗯!“ 2&gt; errorfile ”這個功能就很重要了吧! 了解了嗎? 問:假設我要將 echo "error message" 以 standard error output 的格式來輸出,該如何處置?答:既然有 2&gt;&1 來將 2&gt; 轉到 1&gt; 去,那么應該也會有 1&gt;&2 吧?沒錯!就是這個概念!因此你可以這樣作: ``` [dmtsai@study ~]$ echo "error message" 1&gt;&2 [dmtsai@study ~]$ echo "error message" 2&gt; /dev/null 1&gt;&2 ``` 你會發現第一條有訊息輸出到屏幕上,第二條則沒有訊息!這表示該訊息已經是通過 2&gt; /dev/null 丟到垃圾桶去了! 可以肯定是錯誤訊息啰! ^_^ ### 10.5.2 命令執行的判斷依據: ; , &&, || 在某些情況下,很多指令我想要一次輸入去執行,而不想要分次執行時,該如何是好?基本上你有兩個選擇, 一個是通過第十二章要介紹的 [shell script](../Text/index.html) 撰寫腳本去執行,一種則是通過下面的介紹來一次輸入多重指令喔! * cmd ; cmd (不考慮指令相關性的連續指令下達) 在某些時候,我們希望可以一次執行多個指令,例如在關機的時候我希望可以先執行兩次 sync 同步化寫入磁盤后才 shutdown 計算機,那么可以怎么作呢?這樣做呀: ``` [root@study ~]# sync; sync; shutdown -h now ``` 在指令與指令中間利用分號 (;) 來隔開,這樣一來,分號前的指令執行完后就會立刻接著執行后面的指令了。 這真是方便啊~再來,換個角度來想,萬一我想要在某個目錄下面創建一個文件,也就是說,如果該目錄存在的話, 那我才創建這個文件,如果不存在,那就算了。也就是說這兩個指令彼此之間是有相關性的, 前一個指令是否成功的執行與后一個指令是否要執行有關!那就得動用到 && 或 || 啰! * $? (指令回傳值) 與 && 或 || 如同上面談到的,兩個指令之間有相依性,而這個相依性主要判斷的地方就在于前一個指令執行的結果是否正確。 還記得本章之前我們曾介紹過[指令回傳值](../Text/index.html#returnvar)吧!嘿嘿!沒錯,您真聰明!就是通過這個回傳值啦! 再復習一次“若前一個指令執行的結果為正確,在 Linux 下面會回傳一個 $? = 0 的值”。 那么我們怎么通過這個回傳值來判斷后續的指令是否要執行呢?這就得要借由“ && ”及“ || ”的幫忙了! 注意喔,兩個 & 之間是沒有空格的!那個 | 則是 [Shift]+[\] 的按鍵結果。 | 指令下達情況 | 說明 | | --- | --- | | cmd1 && cmd2 | 1\. 若 cmd1 執行完畢且正確執行($?=0),則開始執行 cmd2。 2\. 若 cmd1 執行完畢且為錯誤 ($?≠0),則 cmd2 不執行。 | | cmd1 &#124;&#124; cmd2 | 1\. 若 cmd1 執行完畢且正確執行($?=0),則 cmd2 不執行。 2\. 若 cmd1 執行完畢且為錯誤 ($?≠0),則開始執行 cmd2。 | 上述的 cmd1 及 cmd2 都是指令。好了,回到我們剛剛假想的情況,就是想要: (1)先判斷一個目錄是否存在; (2)若存在才在該目錄下面創建一個文件。由于我們尚未介紹如何判斷式 ([test](../Text/index.html#test)) 的使用,在這里我們使用 ls 以及回傳值來判斷目錄是否存在啦! 讓我們進行下面這個練習看看: ``` 范例一:使用 ls 查閱目錄 /tmp/abc 是否存在,若存在則用 touch 創建 /tmp/abc/hehe [dmtsai@study ~]$ ls /tmp/abc && touch /tmp/abc/hehe ls: cannot access /tmp/abc: No such file or directory # ls 很干脆的說明找不到該目錄,但并沒有 touch 的錯誤,表示 touch 并沒有執行 [dmtsai@study ~]$ mkdir /tmp/abc [dmtsai@study ~]$ ls /tmp/abc && touch /tmp/abc/hehe [dmtsai@study ~]$ ll /tmp/abc -rw-rw-r--. 1 dmtsai dmtsai 0 Jul 9 19:16 hehe ``` 看到了吧?如果 /tmp/abc 不存在時,touch 就不會被執行,若 /tmp/abc 存在的話,那么 touch 就會開始執行啰! 很不錯用吧!不過,我們還得手動自行創建目錄,傷腦筋~能不能自動判斷,如果沒有該目錄就給予創建呢? 參考一下下面的例子先: ``` 范例二:測試 /tmp/abc 是否存在,若不存在則予以創建,若存在就不作任何事情 [dmtsai@study ~]$ rm -r /tmp/abc &lt;==先刪除此目錄以方便測試 [dmtsai@study ~]$ ls /tmp/abc &#124;&#124; mkdir /tmp/abc ls: cannot access /tmp/abc: No such file or directory &lt;==真的不存在喔! [dmtsai@study ~]$ ll -d /tmp/abc drwxrwxr-x. 2 dmtsai dmtsai 6 Jul 9 19:17 /tmp/abca &lt;==結果出現了!有進行 mkdir ``` 如果你一再重復“ ls /tmp/abc || mkdir /tmp/abc ”畫面也不會出現重復 mkdir 的錯誤!這是因為 /tmp/abc 已經存在, 所以后續的 mkdir 就不會進行!這樣理解否?好了,讓我們再次的討論一下,如果我想要創建 /tmp/abc/hehe 這個文件, 但我并不知道 /tmp/abc 是否存在,那該如何是好?試看看: ``` 范例三:我不清楚 /tmp/abc 是否存在,但就是要創建 /tmp/abc/hehe 文件 [dmtsai@study ~]$ ls /tmp/abc &#124;&#124; mkdir /tmp/abc && touch /tmp/abc/hehe ``` 上面這個范例三總是會嘗試創建 /tmp/abc/hehe 的喔!不論 /tmp/abc 是否存在。那么范例三應該如何解釋呢? 由于Linux 下面的指令都是由左往右執行的,所以范例三有幾種結果我們來分析一下: * (1)若 /tmp/abc 不存在故回傳 $?≠0,則 (2)因為 || 遇到非為 0 的 $? 故開始 mkdir /tmp/abc,由于 mkdir /tmp/abc 會成功進行,所以回傳 $?=0 (3)因為 && 遇到 $?=0 故會執行 touch /tmp/abc/hehe,最終 hehe 就被創建了; * (1)若 /tmp/abc 存在故回傳 $?=0,則 (2)因為 || 遇到 0 的 $? 不會進行,此時 $?=0 繼續向后傳,故 (3)因為 && 遇到 $?=0 就開始創建 /tmp/abc/hehe 了!最終 /tmp/abc/hehe 被創建起來。 整個流程圖示如下: ![指令依序執行的關系示意圖](https://box.kancloud.cn/2016-05-13_5735737787def.gif)圖10.5.2、指令依序執行的關系示意圖 上面這張圖顯示的兩股數據中,上方的線段為不存在 /tmp/abc 時所進行的指令行為,下方的線段則是存在 /tmp/abc 所在的指令行為。如上所述,下方線段由于存在 /tmp/abc 所以導致 $?=0 ,讓中間的 mkdir 就不執行了! 并將 $?=0 繼續往后傳給后續的 touch 去利用啦!瞭乎?在任何時刻你都可以拿上面這張圖作為示意! 讓我們來想想下面這個例題吧! 例題:以 ls 測試 /tmp/vbirding 是否存在,若存在則顯示 "exist" ,若不存在,則顯示 "not exist"!答:這又牽涉到邏輯判斷的問題,如果存在就顯示某個數據,若不存在就顯示其他數據,那我可以這樣做: &gt; ls /tmp/vbirding && echo "exist" &#124;&#124; echo "not exist" 意思是說,當 ls /tmp/vbirding 執行后,若正確,就執行 echo "exist" ,若有問題,就執行 echo "not exist" !那如果寫成如下的狀況會出現什么? &gt; ls /tmp/vbirding &#124;&#124; echo "not exist" && echo "exist" 這其實是有問題的,為什么呢?由圖 10.5.2 的流程介紹我們知道指令是一個一個往后執行, 因此在上面的例子當中,如果 /tmp/vbirding 不存在時,他會進行如下動作: 1. 若 ls /tmp/vbirding 不存在,因此回傳一個非為 0 的數值; 2. 接下來經過 &#124;&#124; 的判斷,發現前一個指令回傳非為 0 的數值,因此,程序開始執行 echo "not exist" ,而 echo "not exist" 程序肯定可以執行成功,因此會回傳一個 0 值給后面的指令; 3. 經過 && 的判斷,咦!是 0 啊!所以就開始執行 echo "exist" 。 所以啊,嘿嘿!第二個例子里面竟然會同時出現 not exist 與 exist 呢!真神奇~ 經過這個例題的練習,你應該會了解,由于指令是一個接著一個去執行的,因此,如果真要使用判斷, 那么這個 && 與 || 的順序就不能搞錯。一般來說,假設判斷式有三個,也就是: > command1 && command2 || command3 而且順序通常不會變,因為一般來說, command2 與 command3 會放置肯定可以執行成功的指令, 因此,依據上面例題的邏輯分析,您就會曉得為何要如此放置啰~這很有用的啦!而且.....考試也很常考~
                  <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>

                              哎呀哎呀视频在线观看