一文帶你簡單理解linux中的輸入輸出重定向
linux簡單理解輸入輸出重定向
linux
重定向可以分為輸出重定向和輸入重定向。在系統(tǒng)中除了標準輸入、標準輸出、錯誤輸出以外,其他的重定向,都需要指定文件描述符id
,也可以稱為句柄。
在linux
中,可以通過查看/proc/進程pid號/fd/
下的文件來查看該進程有多少個fd
,比如:
# ls -l /proc/$$/fd/ total 0 lrwx------. 1 root root 64 Jun 3 22:22 0 -> /dev/pts/0 lrwx------. 1 root root 64 Jun 3 22:22 1 -> /dev/pts/0 lrwx------. 1 root root 64 Jun 3 22:22 2 -> /dev/pts/0 #
上述命令中$$
表示該進程本身的pid
,而該fd
文件下,可以看到有0
、1
、2
三個文件,都指向/dev/pts/0
,這是一個字符設備文件,表示當前的終端。
輸出重定向原理
對于系統(tǒng)而言,任何一個程序都有2個輸出,分別是:
- 文件描述符為1的標準輸出
- 文件描述符為2的錯誤輸出
所以,當執(zhí)行一個命令輸出重定向的時候,比如:
command >> filename
上述命令是將command
命令執(zhí)行的標準輸出結果重定向到filename
文件中,你可以理解為在執(zhí)行該命令的時候,其進程標準輸出文件描述符1
由默認的/dev/pts/0
指向了filename
文件,為此可以來寫一個程序來試試。
程序如下:
#!/bin/bash echo "pid: $$" >&2 while true do echo 123 sleep 3 done
這個程序非常簡單,首先現(xiàn)輸出該腳本的pid
到錯誤輸出上,即文件描述符為2,而后定一個無限循環(huán),每隔3秒輸出123
。
在執(zhí)行的時候,將該文件輸出重定向到filename
中。
# bash test.sh >> filename pid: 42699
程序執(zhí)行會卡主,這是正常的,這是因為有無限循環(huán),每隔3秒會輸出123
字符串至標準輸出上。
而后打開一個新的終端,查看42699
的fd
文件信息。
# ls -l /proc/42699/fd/ total 0 lrwx------. 1 root root 64 Jun 3 23:41 0 -> /dev/pts/0 l-wx------. 1 root root 64 Jun 3 23:41 1 -> /root/fd/filename lrwx------. 1 root root 64 Jun 3 23:41 2 -> /dev/pts/0 lr-x------. 1 root root 64 Jun 3 23:41 255 -> /root/fd/test.sh #
通過上面執(zhí)行的結果可以發(fā)現(xiàn),其標準輸出,文件描述符為1
已經指向一個文件:/root/fd/filename
,而非終端字符設備。所以說,在上面案例中,重定向后,實際上是將句柄給改寫到文件中,所以屏幕沒有輸出任何數(shù)據?;诖?,標準輸入和錯誤輸出的原理也是這樣的。
輸出重定向
輸出重定向一般格式為:[n]>[|]filename
,其中n
是文件描述符,>|
表示覆蓋保護繞過機制,不過一般不用,即常用的寫法為:[n]>filename
。
比如,將字符串abcdef
的標準輸出重定向到filename
中:
echo "abcdef" 1> filename
默認情況下,1>
可以縮略寫為>
,這也是常用的寫法:
echo "abcde" > filename
將命令dasdsada
的錯誤結果寫入到文件filename
中:
dasdsada 2> filename
因為沒有這個命令,所以一定會報錯-bash: dasdsada: command not found
。
對于該重定向而言,它在執(zhí)行前會清理掉原始內容,從而寫入新的內容。
除此之外,還有追加重定向,其格式為[n]>>filename
,其中n
是文件描述符,>>
表示追加,它不會清理掉原有內容。比如將abc
追加到文件filename
中。
echo 123 1>> filename
同樣的,也可以將1>>
縮略寫為>>
。
將命令aaa
的錯誤結果追加寫入到文件filename
中:
aaa 2>> filename
輸入重定向
在linux
系統(tǒng)中,任何一個程序的標準輸入文件描述符id
為0
,而輸入重定向一般格式為[n]<filename
,其中n
表示文件描述符。
所以,如下命令:
cat 0< filename
它的意思是將filename
文件的內容作為標準輸入提供給cat
調用,結果是打印了filename
的內容,上述命令中的0<
可以縮略寫為<
。
不僅如此,還能在循環(huán)中,搭配read
,將文件的信息按行讀取。
比如有以下文件內容:
# cat filename aa bb cc dd #
有腳本內容如下:
#!/bin/bash while read ll do echo read_at: ${ll} done 0< filename
上述腳本表示將filename
文件作為輸入源,供while
調用,按照的方式是read
命令按行調用,將行內容賦值到ll
變量上,這個變量名稱可以自定義。
其結果為:
# bash test.sh read_at: aa read_at: bb read_at: cc read_at: dd #
輸入重定向還有一種表達方式是here-documents
。表示多行定義輸入,其語法為:
command [n]<<word here doc word
其中n
表示文件操作符,如果省略,則使用默認的文件操作符0
,而后是關鍵字<<
,word
是自定義的結束符,讓后續(xù)讀取到word
后停止讀取。
比如:
cat <<END 123 456 789 END
輸出的結果為
123
456
789
上述命令中的END
是可以替換為任何字符串的,只要后續(xù)出現(xiàn)該字符串就會停止輸入,注意這個字符,一定是要在單獨的一行出現(xiàn)的,不能有其他字符,包括空格。
here-documents
會進行命令替換,變量替換等,比如有如下命令:
# x=123 # cat <<END ${x} $(pwd) aa bb cc END
輸出的結果會先進行命令替換,變量替換等,比如將${x}
替換為123
,將$(pwd)
替換為當前目錄。如果不想其被替換,則需要添加單引號進行轉義。
重定向的順序
注意看,如下有2條命令:
ls -l > filename 2>&1
和
ls -l 2>&1 > filename
所執(zhí)行的結果是完全不一樣的,第一條命令是將標準輸出和錯誤輸出都寫入到filename
中,而第二條則是將錯誤輸出輸出到屏幕上,而將標準輸出寫入到文件中,如果不是很明白,可以嘗試拆解一下命令:
首先,命令的前提是:標準輸出 和 錯誤輸出 都在某個設備上,比如pty
終端,假設設備為/dev/pts/0
,所以文件描述符信息為:
1 -> /dev/pts/0
2 -> /dev/pts/0
然后第一條命令,ls -l > filename
其實是將文件描述符1
給指向了文件filename
,這個時候,文件描述符信息為:
1 -> filename
2 -> /dev/pts/0
這個時候再使用2>&1
表示將錯誤消息也寫入到文件描述符為1
的文件中,即filename
,所以最后的文件描述符為:
1 -> filename
2 -> filename
而第二條命令,一開始都是輸出到某個設備上:
1 -> /dev/pts/0
2 -> /dev/pts/0
這個時候,它將錯誤輸出指向2>&1
,而文件描述符為1
是/dev/pts/0
,所以這第一步,就沒動過,而第二部則是將標準輸出指向filename
,即:
1 -> filename
2 -> /dev/pts/0
所以第二條命令,錯誤輸出輸出到屏幕上,而將標準輸出寫入到文件中。
總結
要理解輸入輸出重定向,一定要理解文件的描述符!對于每個進程,都會產生3個默認的文件描述符,分別是 標準輸入、標準輸出 和 錯誤輸出,用文件描述符id
:0
、1
、2
來表示。
其重定向就是修改這些文件描述符的指向,將他們指向到文件中即可。
對于輸入重定向而言,有一種表達方式是here-documents
,它可以和輸出重定向結合,將終端中輸入的文件寫入到文件中,比如:
cat 1>> filename 0<<END a b c d e END
表示將終端輸入的a
、b
... e
字符提供給cat
命令,而cat
將內容重定向到文件filename
中??梢园l(fā)現(xiàn)上面有1>>
表示將標準輸出的內容重定向到某個文件,0<<
表示將標準輸入的內容重定向到某個文件,上述命令中的1>>
可以縮寫為>>
,而0<<
可以縮寫為<<
。
到此這篇關于一文帶你簡單理解linux中的輸入輸出重定向的文章就介紹到這了,更多相關linux輸入輸出重定向內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mac 安裝omyzsh后不執(zhí)行~/.bash_profile、~/.bashrc的完美解決辦法
mac 安裝 omyzsh 后, terminal瞬間格調飆升,但是,terminal init的時候并不會執(zhí)行~/.bash_profile、~/.bashrc等腳本了,什么原因呢?下面小編給大家分享解決辦法,一起看看吧2017-01-01Shell $?獲取函數(shù)返回值或者上一個命令的退出狀態(tài)
這篇文章主要介紹了Shell $?獲取函數(shù)返回值或者上一個命令的退出狀態(tài),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-01-01