Linux -- 重定向STDIN與STDOUT

《Linux命令行與shell腳本編程大全》彼哼,4 E -- Chapter 15

一对妄、理解輸入和輸出

顯示腳本輸出的方法:

  • 在顯示器屏幕上顯示輸出
  • 將輸出重定向到文件中

這兩種方法要么將數(shù)據(jù)輸出全部顯示,要么什么都不顯示敢朱。但有時(shí)將一部分?jǐn)?shù)據(jù)在顯示器上顯示剪菱,另一部分?jǐn)?shù)據(jù)保存到文件中也是不錯(cuò)的。

對(duì)此拴签,了解Linux如何處理輸入輸出能夠幫助你就能將腳本輸出放到正確位置孝常。

接下來(lái)會(huì)介紹如何用標(biāo)準(zhǔn)的Linux輸入和輸出系統(tǒng)來(lái)將腳本輸出導(dǎo)向特定位置。

1. 標(biāo)準(zhǔn)文件描述符

Linux系統(tǒng)將每個(gè)對(duì)象當(dāng)作文件處理蚓哩。這包括輸入和輸出進(jìn)程构灸。Linux用文件描述符( file descriptor )來(lái)標(biāo)識(shí)每個(gè)文件對(duì)象。

文件描述符是一個(gè)非負(fù)整數(shù)岸梨,可以唯一標(biāo)識(shí)會(huì)話中打開的文件喜颁。每個(gè)進(jìn)程一次最多可以有九個(gè)文件描述符。出于特殊目的曹阔,bash shell保留了前三個(gè)文件描述符( 0 半开、 1 和 2 ):

表1

文件描述符 縮 寫 描 述
0 STDIN 標(biāo)準(zhǔn)輸入
1 STDOUT 標(biāo)準(zhǔn)輸出
2 STDERR 標(biāo)準(zhǔn)錯(cuò)誤

這三個(gè)特殊文件描述符會(huì)處理腳本的輸入和輸出。shell用它們將shell默認(rèn)的輸入和輸出導(dǎo)向到相應(yīng)的位置赃份。

1.1 STDIN

STDIN 文件描述符代表shell的標(biāo)準(zhǔn)輸入寂拆。

對(duì)終端界面來(lái)說(shuō),標(biāo)準(zhǔn)輸入是鍵盤抓韩。shell從 STDIN文件描述符對(duì)應(yīng)的鍵盤獲得輸入纠永,在用戶輸入時(shí)處理每個(gè)字符。在使用輸入重定向符號(hào)( < )時(shí)谒拴,Linux會(huì)用重定向指定的文件來(lái)替換標(biāo)準(zhǔn)輸入文件描述符尝江。

它會(huì)讀取文件并提取數(shù)據(jù),就如同它是鍵盤上鍵入的彪薛。

許多bash命令能接受 STDIN 的輸入茂装,尤其是沒(méi)有在命令行上指定文件的話怠蹂。下面是個(gè)用 cat命令處理 STDIN 輸入的數(shù)據(jù)的例子善延。

$ cat
this is a test
this is a test
this is a second test.
this is a second test.

當(dāng)在命令行上只輸入 cat 命令時(shí),它會(huì)從 STDIN 接受輸入城侧。輸入一行易遣, cat 命令就會(huì)顯示出
一行。

但你也可以通過(guò) STDIN 重定向符號(hào)強(qiáng)制 cat 命令接受來(lái)自另一個(gè)非 STDIN 文件的輸入嫌佑。

$ cat < testfile
This is the first line.
This is the second line.
This is the third line.

現(xiàn)在 cat 命令會(huì)用testfile文件中的行作為輸入豆茫。你可以使用這種技術(shù)將數(shù)據(jù)輸入到任何能從STDIN 接受數(shù)據(jù)的shell命令中侨歉。

1.2 STDOUT

STDOUT 文件描述符代表shell的標(biāo)準(zhǔn)輸出。

在終端界面上揩魂,標(biāo)準(zhǔn)輸出就是終端顯示器幽邓。shell的所有輸出(包括shell中運(yùn)行的程序和腳本)會(huì)被定向到標(biāo)準(zhǔn)輸出中,也就是顯示器火脉。

默認(rèn)情況下牵舵,大多數(shù)bash命令會(huì)將輸出導(dǎo)向 STDOUT 文件描述符。你可以用輸出重定向來(lái)改變倦挂。

$ ls -l > test2
$ cat test2
total 20
-rw-rw-r-- 1 rich rich 53 2014-10-16 11:30 test
-rw-rw-r-- 1 rich rich 0 2014-10-16 11:32 test2
-rw-rw-r-- 1 rich rich 73 2014-10-16 11:23 testfile

通過(guò)輸出重定向符號(hào)畸颅,通常會(huì)顯示到顯示器的所有輸出會(huì)被shell重定向到指定的重定向文件。

你也可以將數(shù)據(jù)追加到某個(gè)文件方援。這可以用 >> 符號(hào)來(lái)完成没炒。

$ who >> test2
$ cat test2
total 20
-rw-rw-r-- 1 rich rich 53 2014-10-16 11:30 test
-rw-rw-r-- 1 rich rich 0 2014-10-16 11:32 test2
-rw-rw-r-- 1 rich rich 73 2014-10-16 11:23 testfile
rich pts/0 2014-10-17 15:34 (192.168.1.2)

who 命令生成的輸出會(huì)被追加到test2文件中已有數(shù)據(jù)的后面。

但是犯戏,如果你對(duì)腳本使用了標(biāo)準(zhǔn)輸出重定向送火,你會(huì)遇到一個(gè)問(wèn)題。下面的例子說(shuō)明了可能會(huì)
出現(xiàn)什么情況先匪。

$ ls -al badfile > test3
ls: cannot access badfile: No such file or directory
$ cat test3
$

當(dāng)命令生成錯(cuò)誤消息時(shí)漾脂,shell并未將錯(cuò)誤消息重定向到輸出重定向文件。shell創(chuàng)建了輸出重定向文件胚鸯,但錯(cuò)誤消息卻顯示在了顯示器屏幕上骨稿。

注意,在顯示test3文件的內(nèi)容時(shí)并沒(méi)有任何錯(cuò)誤姜钳。test3文件創(chuàng)建成功了坦冠,只是里面是空的。

shell對(duì)于錯(cuò)誤消息的處理是跟普通輸出是分開的哥桥。如果你創(chuàng)建了在后臺(tái)模式下運(yùn)行的shell腳本辙浑,通常你必須依賴發(fā)送到日志文件的輸出消息。用這種方法的話拟糕,如果出現(xiàn)了錯(cuò)誤信息判呕,這些信息是不會(huì)出現(xiàn)在日志文件中的。你需要換種方法來(lái)處理送滞。

1.3 STDERR

shell通過(guò)特殊的 STDERR 文件描述符來(lái)處理錯(cuò)誤消息侠草。 STDERR 文件描述符代表shell的標(biāo)準(zhǔn)錯(cuò)誤輸出。

shell或shell中運(yùn)行的程序和腳本出錯(cuò)時(shí)生成的錯(cuò)誤消息都會(huì)發(fā)送到這個(gè)位置犁嗅。

默認(rèn)情況下边涕, STDERR 文件描述符會(huì)和 STDOUT 文件描述符指向同樣的地方(盡管分配給它們的文件描述符值不同)。也就是說(shuō),默認(rèn)情況下功蜓,錯(cuò)誤消息也會(huì)輸出到顯示器輸出中园爷。

但從上面的例子可以看出, STDERR 并不會(huì)隨著 STDOUT 的重定向而發(fā)生改變式撼。使用腳本時(shí)童社,你常常會(huì)想改變這種行為,尤其是當(dāng)你希望將錯(cuò)誤消息保存到日志文件中的時(shí)候著隆。

2. 重定向錯(cuò)誤

你已經(jīng)知道如何用重定向符號(hào)來(lái)重定向 STDOUT 數(shù)據(jù)叠洗。重定向 STDERR 數(shù)據(jù)也沒(méi)太大差別,只要在使用重定向符號(hào)時(shí)定義 STDERR 文件描述符就可以了旅东。有幾種辦法實(shí)現(xiàn)方法灭抑。

2.1 只重定向錯(cuò)誤

你在表1中已經(jīng)看到, STDERR 文件描述符被設(shè)成 2 抵代√诮冢可以選擇只重定向錯(cuò)誤消息,將該文件描述符值放在重定向符號(hào)前荤牍。該值必須緊緊地放在重定向符號(hào)前案腺,否則不會(huì)工作。

$ ls -al badfile 2> test4
$ cat test4
ls: cannot access badfile: No such file or directory

現(xiàn)在運(yùn)行該命令康吵,錯(cuò)誤消息不會(huì)出現(xiàn)在屏幕上了劈榨。該命令生成的任何錯(cuò)誤消息都會(huì)保存在輸出文件中。

用這種方法晦嵌,shell會(huì)只重定向錯(cuò)誤消息同辣,而非普通數(shù)據(jù)。

這里是另一個(gè)將 STDOUT 和STDERR 消息混雜在同一輸出中的例子惭载。

$ ls -al test badtest test2 2> test5
-rw-rw-r-- 1 rich rich 158 2014-10-16 11:32 test2
$ cat test5
ls: cannot access test: No such file or directory
ls: cannot access badtest: No such file or directory

ls 命令的正常 STDOUT 輸出仍然會(huì)發(fā)送到默認(rèn)的 STDOUT 文件描述符旱函,也就是顯示器。

由于該命令將文件描述符 2 的輸出( STDERR )重定向到了一個(gè)輸出文件描滔,shell會(huì)將生成的所有錯(cuò)誤消息直接發(fā)送到指定的重定向文件中棒妨。

2.2 重定向錯(cuò)誤和數(shù)據(jù)

如果想重定向錯(cuò)誤和正常輸出,必須用兩個(gè)重定向符號(hào)含长。需要在符號(hào)前面放上待重定向數(shù)據(jù)所對(duì)應(yīng)的文件描述符券腔,然后指向用于保存數(shù)據(jù)的輸出文件。

$ ls -al test test2 test3 badtest 2> test6 1> test7
$ cat test6
ls: cannot access test: No such file or directory
ls: cannot access badtest: No such file or directory
$ cat test7
-rw-rw-r-- 1 rich rich 158 2014-10-16 11:32 test2
-rw-rw-r-- 1 rich rich 0 2014-10-16 11:33 test3

shell利用 1> 符號(hào)將 ls 命令的正常輸出重定向到了test7文件拘泞,而這些輸出本該是進(jìn)入 STDOUT的纷纫。所有本該輸出到 STDERR 的錯(cuò)誤消息通過(guò) 2> 符號(hào)被重定向到了test6文件。

可以用這種方法將腳本的正常輸出和腳本生成的錯(cuò)誤消息分離開來(lái)田弥。這樣就可以輕松地識(shí)別出錯(cuò)誤信息涛酗,再不用在成千上萬(wàn)行正常輸出數(shù)據(jù)中翻騰了。

另外偷厦,如果愿意商叹,也可以將 STDERR 和 STDOUT 的輸出重定向到同一個(gè)輸出文件。為此bash shell
提供了特殊的重定向符號(hào) &> 只泼。

$ ls -al test test2 test3 badtest &> test7
$ cat test7
ls: cannot access test: No such file or directory
ls: cannot access badtest: No such file or directory
-rw-rw-r-- 1 rich rich 158 2014-10-16 11:32 test2
-rw-rw-r-- 1 rich rich 0 2014-10-16 11:33 test3

當(dāng)使用 &> 符時(shí)剖笙,命令生成的所有輸出都會(huì)發(fā)送到同一位置,包括數(shù)據(jù)和錯(cuò)誤请唱。

你會(huì)注意到其中一條錯(cuò)誤消息出現(xiàn)的位置和預(yù)想中的不一樣弥咪。badtest文件(列出的最后一個(gè)文件)的這條錯(cuò)誤消息出現(xiàn)在輸出文件中的第二行。為了避免錯(cuò)誤信息散落在輸出文件中十绑,相較于標(biāo)準(zhǔn)輸出聚至,bashshell自動(dòng)賦予了錯(cuò)誤消息更高的優(yōu)先級(jí)。這樣你能夠集中瀏覽錯(cuò)誤信息了本橙。

二扳躬、在腳本中重定向輸出

可以在腳本中用 STDOUT 和 STDERR 文件描述符以在多個(gè)位置生成輸出,只要簡(jiǎn)單地重定向相應(yīng)的文件描述符就行了甚亭。有兩種方法來(lái)在腳本中重定向輸出:

  • 臨時(shí)重定向行輸出
  • 永久重定向腳本中的所有命令

1. 臨時(shí)重定向

如果有意在腳本中生成錯(cuò)誤消息贷币,可以將單獨(dú)的一行輸出重定向到 STDERR 。你所需要做的是使用輸出重定向符來(lái)將輸出信息重定向到 STDERR 文件描述符亏狰。

在重定向到文件描述符時(shí)役纹,你必須在文件描述符數(shù)字之前加一個(gè) & :

echo "This is an error message" >&2

這行會(huì)在腳本的 STDERR 文件描述符所指向的位置顯示文本,而不是通常的 STDOUT 暇唾。下面這個(gè)例子就利用了這項(xiàng)功能促脉。

$ cat test8
#!/bin/bash
# testing STDERR messages
echo "This is an error" >&2
echo "This is normal output"

這行會(huì)在腳本的 STDERR 文件描述符所指向的位置顯示文本,而不是通常的 STDOUT 策州。下面這
個(gè)例子就利用了這項(xiàng)功能嘲叔。

$ cat test8
#!/bin/bash
testing STDERR messages
echo "This is an error" >&2
echo "This is normal output"
$
#如果像平常一樣運(yùn)行這個(gè)腳本,你可能看不出什么區(qū)別抽活。
$ ./test8
This is an error
This is normal output

記住硫戈,默認(rèn)情況下,Linux會(huì)將 STDERR 導(dǎo)向 STDOUT 下硕。但是丁逝,如果你在運(yùn)行腳本時(shí)重定向了STDERR ,腳本中所有導(dǎo)向 STDERR 的文本都會(huì)被重定向梭姓。

$ ./test8 2> test9
This is normal output
$ cat test9
This is an error
$

太好了霜幼!通過(guò) STDOUT 顯示的文本顯示在了屏幕上,而發(fā)送給 STDERR 的 echo 語(yǔ)句的文本則被重定向到了輸出文件誉尖。

這個(gè)方法非常適合在腳本中生成錯(cuò)誤消息罪既。如果有人用了你的腳本,他們可以像上面的例子中那樣輕松地通過(guò) STDERR 文件描述符重定向錯(cuò)誤消息。

2. 永久重定向

如果腳本中有大量數(shù)據(jù)需要重定向琢感,那重定向每個(gè) echo 語(yǔ)句就會(huì)很煩瑣丢间。取而代之,你可以用 exec 命令告訴shell在腳本執(zhí)行期間重定向某個(gè)特定文件描述符驹针。

$ cat test10
#!/bin/bash
# redirecting all output to a file
exec 1>testout
echo "This is a test of redirecting all output"
echo "from a script to another file."
echo "without having to redirect every individual line"
$ ./test10
$ cat testout
This is a test of redirecting all output
from a script to another file.
without having to redirect every individual line

exec 命令會(huì)啟動(dòng)一個(gè)新shell并將 STDOUT 文件描述符重定向到文件烘挫。腳本中發(fā)給 STDOUT 的所有輸出會(huì)被重定向到文件。

可以在腳本執(zhí)行過(guò)程中重定向 STDOUT 柬甥。

$ cat test11
#!/bin/bash
# redirecting output to different locations
exec 2>testerror
echo "This is the start of the script"
echo "now redirecting all output to another location"
exec 1>testout
echo "This output should go to the testout file"
echo "but this should go to the testerror file" >&2
$
$ ./test11
This is the start of the script
now redirecting all output to another location
$ cat testout
This output should go to the testout file
$ cat testerror
but this should go to the testerror file

這個(gè)腳本用 exec 命令來(lái)將發(fā)給 STDERR 的輸出重定向到文件 testerror 饮六。接下來(lái),腳本用echo 語(yǔ)句向 STDOUT 顯示了幾行文本苛蒲。隨后再次使用 exec 命令來(lái)將 STDOUT 重定向到 testout 文件卤橄。

注意,盡管 STDOUT 被重定向了臂外,但你仍然可以將 echo 語(yǔ)句的輸出發(fā)給 STDERR 窟扑,在本例中還是重定向到 testerror 文件。

當(dāng)你只想將腳本的部分輸出重定向到其他位置時(shí)(如錯(cuò)誤日志)寄月,這個(gè)特性用起來(lái)非常方便辜膝。
不過(guò)這樣做的話,會(huì)碰到一個(gè)問(wèn)題漾肮。

一旦重定向了 STDOUT 或 STDERR 厂抖,就很難再將它們重定向回原來(lái)的位置。如果你需要在重定
向中來(lái)回切換的話克懊,有個(gè)辦法可以用忱辅。15.4節(jié)將會(huì)討論該方法以及如何在腳本中使用。

3. 在腳本中重定向輸入

你可以使用與腳本中重定向 STDOUT 和 STDERR 相同的方法來(lái)將 STDIN 從鍵盤重定向到其他位置谭溉。 exec 命令允許你將 STDIN 重定向到Linux系統(tǒng)上的文件中:

exec 0< testfile

這個(gè)命令會(huì)告訴shell它應(yīng)該從文件 testfile 中獲得輸入墙懂,而不是 STDIN 。這個(gè)重定向只要在腳本需要輸入時(shí)就會(huì)作用扮念。下面是該用法的實(shí)例损搬。

$ cat test12
#!/bin/bash
# redirecting file input
exec 0< testfile
count=1
while read line
do
    echo "Line #$count: $line"
    count=$[ $count + 1 ]
done
$ ./test12
Line #1: This is the first line.
Line #2: This is the second line.
Line #3: This is the third line.

第14章介紹了如何使用 read 命令讀取用戶在鍵盤上輸入的數(shù)據(jù)。將 STDIN 重定向到文件后柜与,當(dāng) read 命令試圖從 STDIN 讀入數(shù)據(jù)時(shí)巧勤,它會(huì)到文件去取數(shù)據(jù),而不是鍵盤弄匕。

這是在腳本中從待處理的文件中讀取數(shù)據(jù)的絕妙辦法颅悉。Linux系統(tǒng)管理員的一項(xiàng)日常任務(wù)就是從日志文件中讀取數(shù)據(jù)并處理。這是完成該任務(wù)最簡(jiǎn)單的辦法迁匠。

三剩瓶、在腳本中重定向輸入

四驹溃、創(chuàng)建自己的重定向


未完

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市延曙,隨后出現(xiàn)的幾起案子豌鹤,更是在濱河造成了極大的恐慌,老刑警劉巖搂鲫,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件傍药,死亡現(xiàn)場(chǎng)離奇詭異磺平,居然都是意外死亡魂仍,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門拣挪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)擦酌,“玉大人,你說(shuō)我怎么就攤上這事菠劝∩薏埃” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵赶诊,是天一觀的道長(zhǎng)笼平。 經(jīng)常有香客問(wèn)我,道長(zhǎng)舔痪,這世上最難降的妖魔是什么寓调? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮锄码,結(jié)果婚禮上夺英,老公的妹妹穿的比我還像新娘。我一直安慰自己滋捶,他們只是感情好痛悯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著重窟,像睡著了一般载萌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上巡扇,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天扭仁,我揣著相機(jī)與錄音,去河邊找鬼霎迫。 笑死斋枢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的知给。 我是一名探鬼主播瓤帚,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼描姚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了戈次?” 一聲冷哼從身側(cè)響起轩勘,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怯邪,沒(méi)想到半個(gè)月后绊寻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡悬秉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年澄步,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片和泌。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡村缸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出武氓,到底是詐尸還是另有隱情梯皿,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布县恕,位于F島的核電站东羹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏忠烛。R本人自食惡果不足惜属提,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望况木。 院中可真熱鬧垒拢,春花似錦、人聲如沸火惊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)屹耐。三九已至尸疆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惶岭,已是汗流浹背寿弱。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留按灶,地道東北人症革。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鸯旁,于是被迫代替她去往敵國(guó)和親噪矛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子量蕊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容