1、概念
在解釋什么是重定向之前,先來說說什么是文件描述符
Linux 文件描述符
文件描述符可以理解為 Linux 系統為文件分配的一個數字,范圍是 0-3 ,用戶也可以自定義文件描述符,但是自定文件描述符不在這里的討論范圍
文件描述符(file descriptor)
| 名稱 | 類型 | 文件描述符 | 操作 |
|---|---|---|---|
| 標准輸入 | standard input | 0 | <,<< |
| 標准輸出 | standard output | 1 | >,>> |
| 標准錯誤輸出 | standard error output | 2 | 2>,2>> |
文件描述符的存儲位置位於 /proc/self/fd ,文件描述符是通過一系列軟鏈接指向的默認輸出設備,這里我們的默認設備就是模擬終端
模擬終端的文件可以使用命令 tty 來查看
[divent@bash]$ ls -al /proc/self/fd
total 0
lrwx------. 1 divent divent 64 Aug 15 14:09 0 -> /dev/pts/0
lrwx------. 1 divent divent 64 Aug 15 14:09 1 -> /dev/pts/0
lrwx------. 1 divent divent 64 Aug 15 14:09 2 -> /dev/pts/0
對於一條 Linux 的命令執行的過程如下

- 用戶開始從鍵盤(鍵盤在 Linux 上屬於文件)輸入數據,也就是系統從文件中讀取數據的時候
- shell 將接受到的數據(標准輸入)傳遞給相應的命令開始執行
- (yes)執行成功后,即可獲得標准正確輸出。(no)執行失敗后,獲得標准錯誤輸出
- 在默認情況下,標准正確輸出的結果與標准錯誤輸出的缺省輸出都為當前用戶執行的終端
一個命令執行以前,會准備好所有的輸入輸出,默認分別綁定 stdin(0),stdout(1),stderr(2)。如果在准備命令的時候出現錯誤,那么這個命令將不會執行
2、輸出重定向
格式
command [OPTION]{>,>>} [File]
option:
1 standard output(default)
2 standard error output
& all output
>為覆蓋輸出,>>為追加輸出
示例
#假設當前文件夾有文件 test2
[divent@bash]$ ls test test2
ls: cannot access test: No such file or directory
test2
這里可以看到同時擁有的標准輸出與標准錯誤輸出都顯示在了屏幕上
現在我們要將輸出寫入到文件中
#假設已經有文件 test2 , test3
[divent@bash]$ ls test test2 > test3
ls: cannot access test: No such file or directory
[divent@bash]$ cat test3
test2
因為這里的文件只默認接受了標准輸出,所以標准錯誤輸出就輸出到了終端上
我們也可以將標准錯誤輸出寫入到文件
#假設已經有文件 test2 , stderr
[divent@bash]$ ls test test2 2> stderr
test2
[divent@bash]$ cat stderr
ls: cannot access test: No such file or directory
這里獲得的結果就和剛剛的結果正好相反
我們也可以將標准輸出與標准錯誤輸出都重定向到不同的文件
#假設已經有文件 test2 , stdout , stderr
[divent@bash]$ ls test test2 1> stdout 2>stderr
[divent@bash]$ cat stdout
test2
[divent@bash]$ cat stderr
ls: cannot access test: No such file or directory
這里我們就將兩個不同的輸出輸出到了指定的文件中
我們也可以將兩個輸出同時輸出到同一個文件中
#假設已經有文件 test2 , test3
[divent@bash]$ ls test test2 &> test3
[divent@bash]$ cat test3
ls: cannot access test: No such file or directory
test2
這里就使用 & 將兩種輸出同時輸出到了同一個文件
我們也可以只接受某一種輸出,而將其他的輸出導向到其他地方
#假設已經有文件 test2
[divent@bash]$ ls test test2 2>&-
test2
[divent@bash]$ ls test test2 2>/dev/null
test2
# &- 意義為關閉這個輸出,/dev/null 是 linux 的黑洞設備
注意
- shell遇到
>操作符,會判斷右邊文件是否存在,如果存在就先刪除,並且創建新文件。不存在直接創建。 無論左邊命令執行是否成功。右邊文件都會變為空。 >>操作符,判斷右邊文件是否存在,如果不存在,先創建。以添加方式打開文件,會分配一個文件描述符[不特別指定,默認為1]然后,與左邊對應的輸出綁定。- 一條命令在執行前,先會檢查輸出是否正確,如果輸出設備錯誤,將不會進行命令執行
3、輸入重定向
格式
command {<} [File] {<<} [Word]
這里的
<與<<意義不是類似於輸出重定向的操作符,<是從文件中取出數據到指定的文件中
示例
[divent@bash]$ cat > newfile
123
abc
456
[divent@bash]$cat newfile
123
abc
456
#這里使用 Ctrl + D 可以結束輸入,從鍵盤輸入的數據會保存存到 newfile 文件中
cat 命令直接使用的話可以直接接收鍵盤的輸入
現在來嘗試從文件中輸入
#這里的示例我們使用剛才創建的 test3 文件
[divent@bash]$ cat test3
ls: cannot access test: No such file or directory
test2
[divent@bash]$ cat > newfile < test3
[divent@bash]$ cat newfile
ls: cannot access test: No such file or directory
test2
這里的先將文件中的數據提取到了命令 cat 中 ,然后由 cat 寫入到 newfile 中
4、自定義輸入輸出設備
解釋
除了使用系統給你定義的文件描述符以外,用戶還可以自己自定義文件描述符,首先使用 ulimit -n 來查看文件描述符的上限,然后使用命令 exec 來為一個文件添加文件描述符
示例
#首先查看一下現在已經被占用的文件描述符
[divent@bash]$ ls /proc/self/fd
0 1 2 3
#這個時候我們可以使用 exec 命令來為一個文件賦予一個文件描述符
[divent@bash]$ touch /tmp/test && exec 5>/tmp/test
#然后我們再查看文件描述符 5
[divent@bash]$ ls -al /proc/self/fd/5
l-wx------. 1 divent divent 64 Aug 15 14:54 /proc/self/fd/5 -> /tmp/test
#現在我們使用自己自定義的文件描述符來重定向輸出
[divent@bash]$ ls -l /etc >&5
#然后我們再來查看文件中的數據, 因為文件中有數據,這里就只取出前 5 行作為示例
[divent@bash]$ head -n 5 /tmp/test
total 1936
drwxr-xr-x. 3 root root 4096 Jun 10 22:12 abrt
-rw-r--r--. 1 root root 16 Jun 9 16:56 adjtime
-rw-r--r--. 1 root root 1518 Feb 22 22:11 aliases
drwxr-xr-x. 2 root root 4096 Jun 10 22:11 alsa
#我們也可以使用 exec 來將文件的默認輸出指向文件
[divent@bash]$ exec 1>&5
[divent@bash]$ ls -l /etc
#這個時候就會發現沒有輸出了,已經輸出內容已經到了 /tmp/test 中了
#如果想要恢復輸出,將默認輸出重新指向當前 /dev/pts/0 即可
[divent@bash]$ exec 1>/dev/pts/0
#關閉文件描述符
[divent@bash]$ exec 5>&-
#最后我們查看一下
[divent@bash]$ ls /proc/self/fd
0 1 2 3
最后說兩句
- 如果不是很好理解的話,一定要貫徹 Linux 一切皆文件的理念,文件描述符最終也是指向的是文件
- 使用自己自定義的描述符可以簡化一些備份之類的任務
- 在 shell 腳本中,輸入輸出重定向是經常使用的
