<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、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ##shell十三問之11:>與< 差在哪? ---------------- 這次的題目,之前我在CU的shell版說明過了: (原帖的連接在論壇改版后,已經失效) 這次我就不重寫了,將帖子的內容“抄”下來就是了... #### 1. 文件描述符(fd, File Descriptor) ---------- 談到`I/O redirection`,不妨先讓我們認識一下`File Descriptor`(`fd`,文件描述符)。 進程的運算,在大部分情況下,都是進行數據(data)的處理, 這些數據從哪里,讀進來?又輸出到哪里呢? 這就是file descriptor(fd)的功用了。 在shell的進程中,最常使用的`fd`大概有三個,分別為: - 0:standard Input (`STDIN`) - 1: standard output(`STDOUT`) - 2: standard Error output (`STDERR`) 在標準情況下,這些fd分別跟如下設備(device)關聯: - `stdin`(0): keyboard - `stdout`(1): monitor - `stderr`(2): monitor > **Tips:** > linux中的文件描述符(fd)用整數表示。 > linux中任何一個進程都默認打開三個文件, > 這三個文件對應的文件描述符分別是:0, 1, 2; > 即stdin, stdout, stderr. 我們可以用如下命令測試一下: ```shell $ mail -s test root this is a test mail。 please skip. ^d (同時按下ctrl 跟d鍵) ``` 很明顯,`mail`進程所讀進的數據,就是從 `stdin` 也就是keyboard讀進的。 不過,不見得每個進程的`stdin`都跟`mail`一樣 從`keyboard`讀進,因為進程的作者可以從文件參數讀進`stdin`, 如: ```shell $ cat /etc/passwd ``` 但,要是`cat`之后沒有文件參數則如何呢? 哦, 請你自己玩玩看...^_^ ```shell $ cat ``` > **Tips:** > 請留意數據輸出到哪里去了, > 最后別忘了按`ctrl+d`(`^d`), 退出stdin輸入。 至于`stdout`與`stderr`,嗯...等我有空再續吧...^_^ 還是,有哪位前輩來玩接龍呢? 相信,經過上一個練習后, 你對`stdin`與`stdout`應該不難理解了吧? 然后,讓我們看看`stderr`好了。 事實上,`stderr`沒什么難理解的: 說白了就是“錯誤信息”要往哪里輸出而已... 比方說, 若讀進的文件參數不存在的, 那我們在monitor上就看到了: ```shell $ ls no.such.file ls: no.such.file: No such file or directory ``` 若同一個命令,同時成生`stdout`與`stderr`呢? 那還不簡單,都送到monitor來就好了: ```shell $ touch my.file $ ls my.file on.such.file ls: no.such.file: No such file or directory my.file ``` okay, 至此,關于fd及其名稱、還有相關聯的設備, 相信你已經沒問題了吧? --------------------------------------- #### 2. I/O 重定向(I/O Redirection) --------------------------------------- 那好,接下來讓我們看看如何改變這些fd的預設數據通道。 - 用`<` 來改變讀進的數據通道(stdin),使之從指定的文件讀進。 - 用`>` 來改變輸出的數據通道(stdout,stderr),使之輸出到指定的文件。 -------- #####2.1 輸入重定向`n<`(input redirection) -------- 比方說: ```shell $ cat < my.file ``` 就是從my.file讀入數據 ```shell $ mail -s test root < /etc/passwd ``` 則是從/etc/passwd讀入... 這樣一來,stdin將不再是從keyboard讀入, 而是從指定的文件讀入了... 嚴格來說,**`<`符號之前需要指定一個fd的(之前不能有空白),但因為0是`<`的預設值,因此,`<`與`0<`是一樣的***。 okay,這樣好理解了吧? 那要是用兩個`<`,即`<<`又是啥呢? **這是所謂的`here document`, 它可以讓我們輸入一段文本, 直到讀到`<<` 后指定的字符串**。 比方說: ```shell $ cat <<EOF first line here second line here third line here EOF ``` 這樣的話, `cat`會讀入3個句子, 而無需從keyboard讀進數據且要等到(ctrl+d, ^d)結束輸入。 ------------- #####2.2 重定向輸出`>n`(output redirection) ------------- 當你搞懂了`0<` 原來就是改變`stdin`的數據輸入通道之后, 相信要理解如下兩個redirection就不難了: - `1>` #改變stdout的輸出通道; - `2>` #改變stderr的輸出通道; 兩者都是將原來輸出到monitor的數據, 重定向輸出到指定的文件了。 **由于1是`>`的預設值, 因此,`1>`與`>`是相同的,都是改變`stdout`**. 用上次的ls的例子說明一下好了: ```shell $ ls my.file no.such.file 1>file.out ls: no.such.file: No such file or directory ``` 這樣monitor的輸出就只剩下`stderr`的輸出了, 因為`stdout`重定向輸出到文件file.out去了。 ```shell $ ls my.file no.such.file 2>file.err my.file ``` 這樣monitor就只剩下了`stdout`, 因為`stderr`重定向輸出到文件file.err了。 ```shell $ ls my.file no.such.file 1>file.out 2>file.err ``` 這樣monitor就啥也沒有了, 因為`stdout`與`stderr`都重定向輸出到文件了。 呵呵,看來要理解`>`一點也不難啦是不? 沒騙你吧? ^_^ **不過有些地方還是要注意一下的**。 ```shell $ ls my.file no.such.file 1>file.both 2>file.both ``` 假如`stdout`(1)與`stderr`(2)都同時在寫入file.both的話, 則是采取"覆蓋"的方式:后來寫入覆蓋前面的。 讓我們假設一個`stdout`與`stderr`同時寫入到file.out的情形好了; - 首先`stdout`寫入10個字符 - 然后`stderr`寫入6個字符 那么,這時原本的`stdout`輸出的10個字符, 將被`stderr`輸出的6個字符覆蓋掉了。 那如何解決呢?所謂山不轉路轉,路不轉人轉嘛, 我們可以換一個思維: 將`stderr`導進`stdout` 或者將`stdout`導進到`stderr`, 而不是大家在搶同一份文件,不就行了。 bingo就是這樣啦: - 2>&1 #將`stderr`并進`stdout`輸出 - 1>&2 或者 >&2 #將`stdout`并進`stderr`輸出。 于是,前面的錯誤操作可以改寫為: ```shell $ ls my.file no.such.file 1>file.both 2>&1 $ ls my.file no.such.file 2>file.both >&2 ``` 這樣,不就皆大歡喜了嗎? ~~~ ^_^ 不過,光解決了同時寫入的問題還不夠, 我們還有其他技巧需要了解的。 故事還沒有結束,別走開廣告后,我們在回來.... ------ #####2.3 I/O重定向與linux中的`/dev/null` ------ okay,這次不講I/O Redirection, 請佛吧... (有沒有搞錯?`網中人`是否頭殼燒壞了?...)嘻~~~^_^ 學佛的最高境界,就是"四大皆空"。 至于是空哪四大塊,我也不知,因為我還沒有到那個境界.. 這個“空”字,卻非常值得反復把玩: ---色即是空,空即是色 好了,施主要是能夠領會"空"的禪意,那離修成正果不遠了。 在linux的文件系統中,有個設備文件: `/dev/null`. 許多人都問過我,那是什么玩意兒? 我跟你說好了,那就是"空"啦。 沒錯空空如也的空就是null了... 請問施主是否忽然有所頓悟了呢? 然則恭喜了。 這個null在 I/O Redirection中可有用的很呢? - 將fd `1`跟fd `2`重定向到/dev/null去,就可忽略stdout, stderr的輸出。 - 將fd `0`重定向到/dev/null,那就是讀進空(nothing). 比方說,我們在執行一個進程時,會同時輸出到stdout與stderr, 假如你不想看到stderr(也不想存到文件), 那就可以: ```shell $ ls my.file no.such.file 2>/dev/null my.file ``` 若要相反:只想看到stderr呢? 還不簡單將stdout,重定向的/dev/null就行: ```shell $ ls my.file no.such.file >/dev/null ls: no.such.file: No such file or directory ``` 那接下來,假如單純的只跑進程,而不想看到任何輸出呢? 哦,這里留了一手,上次沒講的法子,專門贈與有緣人... ^_^ 除了用 `>/dev/null 2>&1`之外,你還可以如此: ```shell $ ls my.file no.such.file &>/dev/null ``` > **Tips:** >將&>換成>&也行! ------ #####2.4 重定向輸出append (`>>`) ------- okay? 請完佛,接下來,再讓我們看看如下情況: ```shell $ echo "1" > file.out $ cat file.out 1 $ echo "2" > file.out $ cat file.out 2 ``` 看來,我們在重定向stdout或stderr進一個文件時, 似乎永遠只能獲得最后一次的重定向的結果. 那之前的內容呢? 呵呵,要解決這個問題,很簡單啦,將`>`換成`>>` 就好了; ```shell $ echo "3" >> file.out $ cat file.out 2 3 ``` 如此一來,被重定向的文件的之前的內容并不會丟失, 而新的內容則一直追加在最后面去。so easy?... 但是,只要你再次使用`>`來重定向輸出的話, 那么,原來文件的內容被truncated(清洗掉)。 這是,你要如何避免呢? ----備份, yes,我聽到了,不過,還有更好的嗎? 既然與施主這么有緣分,老衲就送你一個錦囊妙法吧: ```shell $ set -o noclobber $ echo "4" > file.out -bash:file: cannot overwrite existing file. ``` 那,要如何取消這個限制呢? 哦,將`set -o `換成 `set +o`就行了: ```shell $ set +o noclobber $ echo "5" > file.out $ cat file.out 5 ``` 再問:那有辦法不取消而又“臨時”改寫目標文件嗎? 哦,佛曰:不可告也。 啊,~~~開玩笑的,開玩笑啦~~~^_^, 哎,早就料到人心是不足的了 ```shell $ set -o noclobber $ echo "6" >| file.out $ cat file.out 6 ``` 留意到沒有: **在`>`后面加個`|`就好, 注意: `>`與`|`之間不能有空白哦**... ----- #####2.5 I/O Redirection的優先級 ----- 呼....(深呼吸吐納一下吧)~~~ ^_^ 再來還有一個難題要你去參透呢: ```shell $ echo "some text here" >file $ cat < file some text here $cat < file >file.bak $cat < file.bak some text here $cat < file >file ``` 嗯?注意到沒有? ---怎么最后那個cat命令看到file是空的呢? why? why? why? 前面提到:`$cat < file > file`之后, 原本有內容的文件,結果卻被清空了。 要理解這個現象其實不難, 這只是priority的問題而已: ** 在IO Redirection中, stdout與stderr的管道先準備好, 才會從stdin讀入數據。** 也就是說,在上例中,`>file`會將file清空, 然后才讀入 `< file`。 但這時候文件的內容已被清空了,因此就變成了讀不進任何數據。 哦,~~~原來如此~~~^_^ 那...如下兩例又如何呢? ```shell $ cat <> file $ cat < file >>file ``` 嗯...同學們,這兩個答案就當練習題嘍, 下課前交作業。 > **Tips:** > 我們了解到`>file`能夠快速把文件file清空; > 或者使用`:>file`同樣可以清空文件, >`:>file`與`>file`的功能: >若文件file存在,則將file清空; 否則,創建空文件file (等效于`touch file`); >二者的差別在于`>file`的方式不一定在所有的shell的都可用。 > `exec 5<>file; echo "abcd" >&5; cat <&5` >將file文件的輸入、輸出定向到文件描述符5, >從而描述符5可以接管file的輸入輸出; >因此,`cat <>file`等價于`cat < file`。 > >而`cat < file >>file`則使file內容成幾何級數增長。 好了, I/O Redirection也快講完了, sorry,因為我也只知道這么多而已啦~~~嘻~~~^_^ 不過,還有一樣東東是一定要講的,各位觀眾(請自行配樂~!#@$%): 就是`pipe line`也。 -------------- #####2.6 管道(pipe line) ------------- 談到`pipe line`,我相信不少人都不會陌生: 我們在很多command line上常看到`|`符號就是pipe line了。 不過,pipe line究竟是什么東東呢? 別急別急...先查一下英文字典,看看pipe是什么意思? 沒錯他就是“水管”的意思... 那么,你能想象一下水管是怎樣一個根接一根的嗎? 又, 每根水管之間的input跟output又如何呢? 靈光一閃:原來pipe line的I/O跟水管的I/O是一模一樣的: **上一個命令的stdout接到下一個命令的stdin去了** 的確如此。不管在command line上使用了多少個pipe line, 前后兩個command的I/O是彼此連接的 (恭喜:你終于開放了 ^_^ ) 不過...然而...但是... ...stderr呢? 好問題不過也容易理解: 若水管漏水怎么辦? 也就是說:在pipe line之間, 前一個命令的stderr是不會接進下一個命令的stdin的, 其輸出,若不用2>file的話,其輸出在monitor上來。 這點請你在pipe line運用上務必要注意的。 那,或許你有會問: **有辦法將stderr也喂進下一個命令的stdin嗎?** (貪得無厭的家伙),方法當然是有的,而且,你早已學習過了。 提示一下就好:**請問你如何將stderr合并進stdout一同輸出呢? 若你答不出來,下課后再來問我...(如果你臉皮足夠厚的話...) 或許,你仍意猶未盡,或許,你曾經碰到過下面的問題: 在`cmd1 | cmd2 | cmd3 | ...` 這段pipe line中如何將cmd2的輸出保存到一個文件呢? 若你寫成`cmd1 | cmd2 >file | cmd3`的話, 那你肯定會發現`cmd3`的stdin是空的,(當然了,你都將 水管接到別的水池了) 聰明的你或許會如此解決: ```shell cmd1 | cmd2 >file; cmd3 < file ``` 是的,你可以這樣做,但最大的壞處是: file I/O會變雙倍,在command執行的整個過程中, file I/O是最常見的最大效能殺手。 凡是有經驗的shell操作者,都會盡量避免或降低file I/O的頻度。 那上面問題還有更好的方法嗎? 有的,那就是`tee`命令了。 **所謂的`tee`命令是在不影響原本I/O的情況下, 將stdout賦值到一個文件中去。** 因此,上面的命令行,可以如此執行: ```shell cmd1 | cmd2 | tee file | cmd3 ``` 在預設上,`tee`會改寫目標文件, 若你要改為追加內容的話,那可用-a參數選項。 基本上,pipe line的應用在shell操作上是非常廣泛的。 尤其是在text filtering方面, 如,cat, more, head, tail, wc, expand, tr, grep, sed, awk...等等文字處理工具。 搭配起pipe line 來使用,你會覺得 command line 原來活得如此精彩的。 常讓人有“眾里尋他千百度,驀然回首,那人卻在燈火闌珊處”之感... 好了,關于I/O Redirection的介紹就到此告一段落。 若日后,有空的話,在為大家介紹其他在shell上好玩的東西。
                  <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>

                              哎呀哎呀视频在线观看