一、實驗介紹
1.1 實驗內容
你可能對重定向這個概念感到些許陌生,但你應該在前面的課程中多次見過>
或>>
操作了,并知道他們分別是將標準輸出導向一個文件或追加到一個文件中。這其實就是重定向,將原本輸出到標準輸出的數據重定向到一個文件中,因為標準輸出(/dev/stdout
)本身也是一個文件,我們將命令輸出導向另一個文件自然也是沒有任何問題的。
1.2 實驗知識點
重定向怎么用
文件描述符(0,1,2)
二、數據流重定向
下面我們簡單的回顧一下我們前面經常用到的兩個重定向操作:
echo 'www.shiyanlou.com' >> redirect$ cat redirect
當然前面沒有用到的<和<<操作也是沒有問題的,如你理解的一樣,它們的區別在于重定向的方向不一致而已,>表示是從左到右,<右到左。
2.1 簡單的重定向
在更多了解 Linux 的重定向之前,我們需要先知道一些基本的東西,前面我們已經提到過 Linux 默認提供了三個特殊設備,用于終端的顯示和輸出,分別為stdin(標準輸入,對應于你在終端的輸入),stdout(標準輸出,對應于終端的輸出),stderr(標準錯誤輸出,對應于終端的輸出)。
文件描述符 | 設備文件 | 說明 |
---|---|---|
0 | /dev/stdin | 標準輸入 |
1 | /dev/stdout | 標準輸出 |
2 | /dev/stderr | 標準錯誤 |
文件描述符:文件描述符在形式上是一個非負整數。實際上,它是一個索引值,指向內核為每一個進程所維護的該進程打開文件的記錄表。當程序打開一個現有文件或者創建一個新文件時,內核向進程返回一個文件描述符。在程序設計中,一些涉及底層的程序編寫往往會圍繞著文件描述符展開。但是文件描述符這一概念往往只適用于 UNIX、Linux 這樣的操作系統。
另外還有一個符號-
,它可以同時作為前一個命令的。
我們可以這樣使用這些文件描述符:
默認使用終端的標準輸入作為命令的輸入和標準輸出作為命令的輸出
$ cat (按Ctrl+C退出)
將cat的連續輸出(heredoc方式)重定向到一個文件
cat > Documents/test.c <<EOF#include <stdio.h>int main(){ printf("hello world\n"); return 0;}EOF
將一個文件作為命令的輸入,標準輸出作為命令的輸出
$ cat Documents/test.c
將echo命令通過管道傳過來的數據作為cat命令的輸入,將標準輸出作為命令的輸出
$ echo 'hi' | cat
將echo命令的輸出從默認的標準輸出重定向到一個普通文件
cat redirect
初學者這里要注意不要將管道和重定向混淆,管道默認是連接前一個命令的輸出到下一個命令的輸入,而重定向通常是需要一個文件來建立兩個命令的連接,你可以仔細體會一下上述第三個操作和最后兩個操作的異同點。
2.2 標準錯誤重定向
重定向標準輸出到文件,這是一個很實用的操作,另一個很實用的操作是將標準錯誤重定向,標準輸出和標準錯誤都被指向偽終端的屏幕顯示,所以我們經??吹降囊粋€命令的輸出通常是同時包含了標準輸出和標準錯誤的結果的。比如下面的操作:
使用cat 命令同時讀取兩個文件,其中一個存在,另一個不存在
cat Documents/test.c hello.c > somefile
遺憾的是,這里依然出現了那條錯誤信息,這正是因為如我上面說的那樣,標準輸出和標準錯誤雖然都指向終端屏幕,實際它們并不一樣。那有的時候我們就是要可以隱藏某些錯誤或者警告,那又該怎么做呢。這就需要用到我們前面講的文件描述符了:
將標準錯誤重定向到標準輸出,再將標準輸出重定向到文件,注意要將重定向到文件寫到前面
cat Documents/test.c hello.c &>somefilehell
注意你應該在輸出重定向文件描述符前加上&
,否則shell會當做重定向到一個文件名為1的文件中
2.3 使用tee
命令同時重定向到多個文件
你可能還有這樣的需求,除了需要將輸出重定向到文件,也需要將信息打印在終端。那么你可以使用tee
命令來實現:
$ echo 'hello shiyanlou' | tee hello
2.4 永久重定向
你應該可以看出我們前面的重定向操作都只是臨時性的,即只對當前命令有效,那如何做到“永久”有效呢,比如在一個腳本中,你需要某一部分的命令的輸出全部進行重定向,難道要讓你在每個命令上面加上臨時重定向的操作嘛,當然不需要,我們可以使用exec
命令實現“永久”重定向。exec
命令的作用是使用指定的命令替換當前的 Shell,及使用一個進程替換當前進程,或者指定新的重定向:
先開啟一個子 Shell
exec 1>somefile# 后面你執行的命令的輸出都將被重定向到文件中,直到你退出當前子shell,或取消exec的重定向(后面將告訴你怎么做)
exit$ cat somefile
2.5 創建輸出文件描述符
在 Shell 中有9個文件描述符。上面我們使用了也是它默認提供的0,1,2號文件描述符。另外我們還可以使用3-8的文件描述符,只是它們默認沒有打開而已。你可以使用下面命令查看當前 Shell 進程中打開的文件描述符:
$ cd /dev/fd/;ls -Al
同樣使用exec
命令可以創建新的文件描述符:
exec 3>somefile# 先進入目錄,再查看,否則你可能不能得到正確的結果,然后再回到上一次的目錄
echo "this is test" >&3
exit
2.6 關閉文件描述符
如上面我們打開的3號文件描述符,可以使用如下操作將它關閉:
2.7 完全屏蔽命令的輸出
在 Linux 中有一個被稱為“黑洞”的設備文件,所以導入它的數據都將被“吞噬”。
在類 UNIX 系統中,/dev/null,或稱空設備,是一個特殊的設備文件,它通常被用于丟棄不需要的輸出流,或作為用于輸入流的空文件,這些操作通常由重定向完成。讀取它則會立即得到一個EOF。
我們可以利用設個/dev/null
屏蔽命令的輸出:
$ cat Documents/test.c nefile 1>/dev/null 2>&1
上面這樣的操作將使你得不到任何輸出結果。
2.8 使用 xargs 分割參數列表
xargs 是一條 UNIX 和類 UNIX 操作系統的常用命令。它的作用是將參數列表轉換成小塊分段傳遞給其他命令,以避免參數列表過長的問題。
這個命令在有些時候十分有用,特別是當用來處理產生大量輸出結果的命令如 find,locate 和 grep 的結果,詳細用法請參看 man 文檔。
$ cut -d: -f1 < /etc/passwd | sort | xargs echo
上面這個命令用于將/etc/passwd
文件按:
分割取第一個字段排序后,使用echo
命令生成一個列表。
輕松一下
之前介紹過一個在命令行將圖片轉換為 ascii 字符查看的工具 aview/asciiview,不過它是黑白的?,F在,這里是個彩色的:
cacaview <pic_file>
cacafire
三、作業
1、理解下面這段代碼的的作用,實際這段代碼不會正常工作,請結合這一小節的知識分析這段代碼沒有正確工作的原因,并設法解決這個問題。
如果你還沒有 Shell 腳本編程的基礎,你可以選擇跳過或者到這里高級 Bash 編程指南學習
while read filename; do rm -iv $filenamedone <<(ls)