Shell 命令通常有輸入輸出。預設從標準輸入裝置(stdin)獲取輸入,結果輸出到標準輸出裝置(stdout)顯示。通常:
- 標準輸入裝置:鍵盤
- 標準輸出裝置:終端,即顯示器
Shell 命令執行時都會開啟三個檔案:
- 標準輸入檔案(
stdin):檔案描述符0,從stdin讀取資料 - 標準輸出檔案(
stdout):檔案描述符1,向stdout輸出資料 - 標準錯誤檔案(
stderr):檔案描述符2,向stderr流中寫入錯誤資訊
但是輸入輸出也可來自其它地方,這就是輸入輸出重定向。
1 輸出重定向
1.1 標準輸出重定向
將命令的標準輸出寫到檔案裡:
command 1> log_a.txt # 直接输出,覆盖之前的文件
command 1>> log_b.txt # 添加到之前文件的后面
需要注意command後面的1>和1>>,在1和>或>>之間是沒有空格的。如果按照下面寫法,則1是command的參數。
command 1 > log_a.txt
由於預設是標準輸出,也可以去掉1:
command > log_a.txt
command >> log_a.txt
1.2 標準錯誤重定向
標準錯誤的檔案描述符是2:
command 2>log_a.txt
command 2>>log_a.txt
標準錯誤中的2一定要放置在>或者>>前,且中間沒有空格。
1.3 同時重定向
command >log.txt 2>&1 # 把标准错误和标准输出同时输出到一个文件
command 1>log_a.txt 2>log_b.txt # 将两者输出到不同的文件
輸出檔案合併
n >& m # 将输出文件 m 和 n 合并。
1.4 特殊的/dev/null
/dev/null是一個特殊的檔案,寫入到它的內容都會被丟棄;如果嘗試從該檔案讀取內容,那麼什麼也讀不到。(看起來像個黑洞。)但/dev/null檔案非常有用,將命令的輸出重定向到它,會起到禁止輸出的效果。
command > /dev/null
command 2> /dev/null
command > /dev/null 2>&1
2 輸入重定向
可以理解和輸出重定向相反,輸入來自於檔案。
2.1 輸入重定向
標準輸入是鍵盤,其實也可以從檔案輸入:
shell_command < filea.txt # 将filea.txt的内容作为标准输入
2.2 輸入檔案合併
n <& m #将输入文件 m 和 n 合并。
2.3 Here document
就是在命令列中輸入多行文字:
command << delimiter
document
delimiter
它將兩個delimiter之間的內容(document) 作為輸入傳遞給 command:
- 結尾的
delimiter一定要頂格寫,前面不能有任何字元,後面也不能有任何字元,包括空格和 tab 縮排。 - 開始的 delimiter 前後的空格會被忽略掉。
也可將Here Document用在指令碼中:
#!/bin/bash
cat << EOF
This is a simple lookup program for good (and bad) restaurants
in Cape Town.
EOF
3 輸入輸出重定向
同時處理輸入和輸出的情況。
command < file1 >file2 # 把file1作为标准输入,file2作为标准输出
4 管道命令
4.1 |命令
管道命令(|)將一個命令的輸出,轉換為另外一個命令的輸入。
常見情形如篩選資料夾(如.)中包含特定名字(如y)的檔案:
ls . | grep y
這裡就使用了管道命令|,將ls .的輸出轉換為grep命令的輸入。管道命令可以連續使用,則是ls . | grep y | grep -v x:篩選出所有包含y但是不包含x的檔案。
管道命令會開啟新的執行緒來執行。比如說grep y就和ls .並不在同一個執行緒。
4.2 xargs對輸出進行操作
管道命令的輸出並不一定滿足下一個命令的輸入,有時候需要對管道命令進行一些操作再傳遞為輸入,此時就需要xargs命令。xargs(extended arguments),可以實現:
- 參數處理
- 從檔案中讀取資訊作為輸入
xargs後需要接後續處理的命令,如果沒有顯示指定,則預設為echo。雖然xargs的輸入可以包含空格和換行,但是經過echo的處理,都會變成空格。
ls . | ls -l
這裡報錯原因是ls -l的輸入不對,需要用xargs命令來轉換一下:
ls . | xargs ls -l
常見參數如下,為了說明問題,這裡構建了例子檔案。
➜ cat x.txt
shell_00.md
shell_01.md
shell_02.md
shell_03.md
shell_04.md
shell_05.md
-
-axx 從檔案獲取輸入➜ xargs -a x.txt file shell_00.md: Unicode text, UTF-8 text shell_01.md: Unicode text, UTF-8 text shell_02.md: Unicode text, UTF-8 text shell_03.md: Unicode text, UTF-8 text shell_04.md: Unicode text, UTF-8 text shell_05.md: Unicode text, UTF-8 text -
-p每執行一個參數時詢問一次使用者,需要輸入y+回車鍵 或者yes+回車鍵表示確定,單獨輸入回車鍵表示不執行:➜ xargs -a x.txt -p file file shell_00.md shell_01.md shell_02.md shell_03.md shell_04.md shell_05.md?...yes shell_00.md: Unicode text, UTF-8 text shell_01.md: Unicode text, UTF-8 text shell_02.md: Unicode text, UTF-8 text shell_03.md: Unicode text, UTF-8 text shell_04.md: Unicode text, UTF-8 text shell_05.md: Unicode text, UTF-8 text -
-nnum,命令執行時一次用的參數個數,預設用所有的,如果已經有的參數超過了這個數目,則會分行執行。➜ xargs -a x.txt -p -n 2 file file shell_00.md shell_01.md?...yes shell_00.md: Unicode text, UTF-8 text shell_01.md: Unicode text, UTF-8 text file shell_02.md shell_03.md?...yes shell_02.md: Unicode text, UTF-8 text shell_03.md: Unicode text, UTF-8 text file shell_04.md shell_05.md?...yes shell_04.md: Unicode text, UTF-8 text shell_05.md: Unicode text, UTF-8 text -
-t先列印具體執行的命令,再執行 -
-i或-I,將xargs的每項名稱,一般是一行一行賦值給{},可以用{}代替 -
-rno-run-if-empty 當 xargs 的輸入為空的時候則停止 xargs,不再去執行 -
-L或-lnum 從標準輸入一次讀取 num 行送給後面的命令➜ xargs -a x.txt -t -L 2 file file shell_00.md shell_01.md shell_00.md: Unicode text, UTF-8 text shell_01.md: Unicode text, UTF-8 text file shell_02.md shell_03.md shell_02.md: Unicode text, UTF-8 text shell_03.md: Unicode text, UTF-8 text file shell_04.md shell_05.md shell_04.md: Unicode text, UTF-8 text shell_05.md: Unicode text, UTF-8 text需要和前面
-n做一個區別。這裡指的是輸入的行數,而-n指的是輸出的參數的個數。 -
-ddelimeter 分隔符,預設分隔符是空格,是 xargs 的輸入的分隔➜ echo "ambmcmdm" | xargs -dm a b c d -
-e或-Eflag, e 是 end 的意思,flag 必須是一個以空格分隔的標誌,當 xargs 分析到含有 flag 這個標誌的時候就停止 -
-snum 命令列的最大字元數,xargs 後面那個命令的最大命令列字元數 -
-xexit,配合-s使用 -
-P修改最大的行程數,預設是 1,為 0 時候儘可能多。
4.3 tee命令
tee 讀取標準輸入的資料,並將其內容輸出成檔案。常見參數如下:
-a或--append附加到既有檔案的後面,而非覆蓋它。-i或--ignore-interrupts忽略中斷訊號。
總結
本文介紹了 Shell 中輸入輸出重定向,以及通過管道命令來實現前一命令的輸出作為後一命令的輸入。以此介紹了xargs和tee命令。