【shell筆記>腳本】重定向、標(biāo)準(zhǔn)輸入輸出與錯(cuò)誤

本章內(nèi)容:

  • 再探重定向
  • 標(biāo)準(zhǔn)輸入和輸出
  • 報(bào)告錯(cuò)誤
  • 丟棄數(shù)據(jù)
  • 創(chuàng)建日志文件

理解輸入和輸出

顯示輸出的方法有:

  • 在顯示器屏幕上輸出
  • 將輸出重定向到文件中
  • 有時(shí)將一部分?jǐn)?shù)據(jù)顯示在顯示器上;一部分保存到文件中。

之前涉及的腳本都是以第一種方式輸出。現(xiàn)在我們來(lái)具體了解下輸入和輸出样漆。

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

Linux系統(tǒng)將每個(gè)對(duì)象當(dāng)作文件處理。著包括輸入和輸出進(jìn)程晦闰。而標(biāo)識(shí)文件對(duì)象是通過(guò)文件描述符完成的放祟。文件描述符是一個(gè)非負(fù)整數(shù),可以唯一標(biāo)識(shí)會(huì)話中打開的文件呻右。每個(gè)進(jìn)程一次最多有九個(gè)文件描述符跪妥,bash shell保留勒前三個(gè)(0,1,2),見下表窿冯。

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

shell用他們將shell默認(rèn)的輸入和輸出導(dǎo)向到相應(yīng)的位置骗奖。

STDIN

在使用輸入重定向符號(hào)(<)時(shí),Linux會(huì)用重定向指定的文件來(lái)替換標(biāo)準(zhǔn)輸入文件描述符醒串。它會(huì)讀取文件并提取數(shù)據(jù)执桌,就像它是從鍵盤上鍵入的。

wangsx@SC-201708020022:~/tmp$ cat
this is a test
this is a test
this is a second test
this is a second test

輸入cat命令時(shí)芜赌,它從STDIN接受輸入仰挣。輸入一行,cat命令會(huì)顯示一行缠沈。

當(dāng)然也可以通過(guò)<符號(hào)強(qiáng)制cat命令接受來(lái)自另一個(gè)非STDIN文件的輸入膘壶。

wangsx@SC-201708020022:~$ cat < testfile
This is the first line.
This is the second line.
This is the third line.

STDOUT

標(biāo)準(zhǔn)輸出就是終端顯示器。我們可以使用>輸出重定向符號(hào)來(lái)改變它洲愤。

wangsx@SC-201708020022:~$ ls -l > test2
wangsx@SC-201708020022:~$ cat test2
總用量 28
drwxrwxrwx 0 wangsx wangsx 4096 8月   2 11:48 biosoft
-rw-rw-rw- 1 wangsx wangsx 2156 8月   4 00:12 biostar.yml
drwxrwxrwx 0 wangsx wangsx 4096 8月   3 22:24 miniconda2
drwxrwxrwx 0 wangsx wangsx 4096 8月   2 11:50 ncbi
-rw-rw-rw- 1 wangsx wangsx 5230 8月  14 00:14 spf13-vim.sh
drwxrwxrwx 0 wangsx wangsx 4096 8月  13 23:51 src
-rw-rw-rw- 1 wangsx wangsx    0 8月  21 22:43 test2
-rw-rw-rw- 1 wangsx wangsx   73 8月  21 22:39 testfile
drwxrwxrwx 0 wangsx wangsx 4096 8月  19 17:15 tmp
-rw-rw-rw- 1 wangsx wangsx 2156 8月  14 12:20 wsx_biostar.yml

如果文件存在颓芭,>符號(hào)會(huì)將導(dǎo)向的文件全部重寫。如果想要以追加的形式柬赐,則使用>>亡问。

STDERR

STDERR文件描述符代表shell的標(biāo)準(zhǔn)錯(cuò)誤輸出。運(yùn)行腳本或命令的錯(cuò)誤信息都會(huì)發(fā)送到這個(gè)位置。

默認(rèn)州藕,STDERR會(huì)和STDOUT指向同樣的地方(屏幕終端)束世。使用腳本時(shí),我們常常會(huì)希望將錯(cuò)誤信息保存到日志文件中床玻。

重定向錯(cuò)誤

幾種實(shí)現(xiàn)方法:

  1. 只重定向錯(cuò)誤

    將文件描述符值(2)放在重定向符號(hào)前毁涉。

    wangsx@SC-201708020022:~$ ls -al badfile 2> test4
    wangsx@SC-201708020022:~$ cat test4
    ls: 無(wú)法訪問'badfile': 沒有那個(gè)文件或目錄
    

    命令生成的任何錯(cuò)誤信息都會(huì)保存在輸出文件中。這個(gè)方法只重定向錯(cuò)誤信息锈死。

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

    這必須用兩個(gè)重定向符號(hào)贫堰。需要在符號(hào)前面放上待重定向數(shù)據(jù)所對(duì)應(yīng)的文件描述符,然后指向用于保存數(shù)據(jù)的輸出文件待牵。

    wangsx@SC-201708020022:~$ ls -al test test2 test3 bad test 2> test6 1> test7
    wangsx@SC-201708020022:~$ cat test6
    ls: 無(wú)法訪問'test': 沒有那個(gè)文件或目錄
    ls: 無(wú)法訪問'test3': 沒有那個(gè)文件或目錄
    ls: 無(wú)法訪問'bad': 沒有那個(gè)文件或目錄
    ls: 無(wú)法訪問'test': 沒有那個(gè)文件或目錄
    wangsx@SC-201708020022:~$ cat test7
    -rw-rw-rw- 1 wangsx wangsx 571 8月  21 22:43 test2
    

    可以看到正常輸出重定向到了test7严嗜,錯(cuò)誤重定向到了test6。另外洲敢,也可以將STDERR和STDOUT的輸出重定向到同一個(gè)輸出文件,bash shell提供了符號(hào)&>茄蚯。

    wangsx@SC-201708020022:~$ ls -al test test2 test3 bad &> test7
    wangsx@SC-201708020022:~$ cat test7
    ls: 無(wú)法訪問'test': 沒有那個(gè)文件或目錄
    ls: 無(wú)法訪問'test3': 沒有那個(gè)文件或目錄
    ls: 無(wú)法訪問'bad': 沒有那個(gè)文件或目錄
    -rw-rw-rw- 1 wangsx wangsx 571 8月  21 22:43 test2
    

    使用這個(gè)符號(hào)的話压彭,bash shell會(huì)自動(dòng)賦予錯(cuò)誤消息更高的優(yōu)先級(jí)。這樣能夠集中瀏覽錯(cuò)誤信息渗常。

    ?

在腳本中重定向輸出

兩種方法在腳本中重定向輸出:

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

臨時(shí)重定向

如果有意在腳本中生成錯(cuò)誤信息壮不,可以將單獨(dú)的一行輸出重定向到STDERR。

使用時(shí)需要在文件描述符數(shù)字前加&:

echo "This is an error message" >&2

下面看個(gè)例子:

wangsx@SC-201708020022:~$ cat test8
#!/bin/bash
# testing STDERR message

echo "This is an error" >&2
echo "This is normal output"

像平常一樣運(yùn)行的話皱碘,看出不會(huì)有什么差別询一。

wangsx@SC-201708020022:~$ sh test8
This is an error
This is normal output

但是如果重定向STDERR的話,所有導(dǎo)向STDERR的文本都會(huì)被重定向

wangsx@SC-201708020022:~$ sh test8 2> test9
This is normal output
wangsx@SC-201708020022:~$ cat test9
This is an error

這個(gè)方法非常適合在腳本中生成錯(cuò)誤信息癌椿。

永久重定向

如果腳本中涉及大量重定向健蕊,上述的方法就會(huì)非常繁瑣。我們可以用exec命令告訴shell在腳本執(zhí)行期間重定向某個(gè)特定文件描述符踢俄。

wangsx@SC-201708020022:~$ 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"
wangsx@SC-201708020022:~$ sh test10
wangsx@SC-201708020022:~$ cat testout
This is a test of redirecting all output
from a script to another file
without having to redirect every individual line

再結(jié)合STDERR看看

wangsx@SC-201708020022:~$ 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
wangsx@SC-201708020022:~$ sh test11
This is the start of the script
now redirecting all output to another location
wangsx@SC-201708020022:~$ cat testout
This output should go to the testout file
wangsx@SC-201708020022:~$ cat testerror
but this should go to the testerror file

這個(gè)腳本用exec命令將STDERR的輸出重定向到文件testerror缩功。接著echo語(yǔ)句向STDOUT顯示幾行文本。隨后使用exec命令將STDOUT重定向到testout文件都办。最后嫡锌,雖然STDOUT被重定向了,但依然可以將echo語(yǔ)句發(fā)給STDERR琳钉。

這里存在一個(gè)問題势木,一旦重定向了STDOUT或STDERR,就很難將他們重定向回原來(lái)的位置歌懒。

這個(gè)問題可以用以下方式解決啦桌。

前面提到shell只用了3個(gè)文件描述符,而總共有9個(gè)歼培,我們可以利用其他6個(gè)來(lái)操作震蒋。

這里只需要另外使用一個(gè)茸塞,就可以重定向文件描述符:

wangsx@SC-201708020022:~$ cat test14
#!/bin/bash
# storing STDOUT, the coming back to it

exec 3>&1
exec 1>test14out

echo "This should store in the output file"
echo "along with this line"

exec 1>&3
echo "Now things should be back to normal"
wangsx@SC-201708020022:~$ sh test14
Now things should be back to normal
wangsx@SC-201708020022:~$ cat test14out
This should store in the output file
along with this line

這里有意思的是把重定向當(dāng)程序變量在玩,類似

a=b # 把b的內(nèi)容存到a
b=c # 修改b的內(nèi)容
# 使用完后
b=a # 將b原來(lái)的內(nèi)容還原

輸入文件描述符也可以進(jìn)行類似的操作查剖。

阻止命令輸出

有時(shí)候不想顯示腳本的輸出就要這么干钾虐。

一種通用的方法是將STDERR重定向到null的特殊文件(里面什么都沒有)。shell輸出到null文件的任何數(shù)據(jù)都不會(huì)保存笋庄,全部被丟掉了效扫。

null文件在Linux中的標(biāo)準(zhǔn)位置是/dev/null

wangsx@SC-201708020022:~$ ls -al > /dev/null
wangsx@SC-201708020022:~$ cat /dev/null
wangsx@SC-201708020022:~$

這是避免出現(xiàn)錯(cuò)誤消息直砂,也無(wú)需保存它們的一個(gè)常用方法菌仁。

wangsx@SC-201708020022:~$ ls -al badfile test2 2> /dev/null
-rw-rw-rw- 1 wangsx wangsx 571 8月  21 22:43 test2

由于null文件不含有任何內(nèi)容,程序員通常用它來(lái)快速清除現(xiàn)有文件中的數(shù)據(jù)静暂,而不用先刪除文件再重新創(chuàng)建济丘。

wangsx@SC-201708020022:~$ cat testfile
This is the first line.
This is the second line.
This is the third line.
wangsx@SC-201708020022:~$ cat /dev/null > testfile
wangsx@SC-201708020022:~$ cat testfile
wangsx@SC-201708020022:~$

創(chuàng)建臨時(shí)文件

Linux使用/tmp目錄來(lái)存放不需要永久保留的文件。大多數(shù)Linux發(fā)行版配置了在啟動(dòng)時(shí)刪除/tmp目錄的所有文件洽蛀。

創(chuàng)建本地臨時(shí)文件

默認(rèn)mktemp會(huì)在本地目錄創(chuàng)建一個(gè)文件摹迷。你只需要指定文件名模板,可以是任意文本名郊供,后面加六個(gè)X即可峡碉。

wangsx@SC-201708020022:~/tmp$ mktemp testing.XXXXXX
wangsx@SC-201708020022:~/tmp$ mktemp testing.XXXXXX
wangsx@SC-201708020022:~/tmp$ ll
總用量 12
drwxrwxrwx 0 wangsx wangsx 4096 8月  22 21:34 ./
drwxr-xr-x 0 wangsx wangsx 4096 8月  22 21:31 ../
-rw------- 1 wangsx wangsx    0 8月  22 21:33 testing.R6dAku
-rw------- 1 wangsx wangsx    0 8月  22 21:32 testing.V5psXP

mktemp命令會(huì)用6個(gè)字符碼替換這6個(gè)X,從而保證文件名在目錄中是唯一的驮审。

在腳本中使用mktemp命令時(shí)鲫寄,可能要將文件名保存到變量中,這樣就可以在腳本后面引用了疯淫。

wangsx@SC-201708020022:~/tmp$ cat test19
#!/bin/bash t nomore" \
# creating and using a temp file
tempfile=$(mktemp test19.XXXXXX)

exec 3>$tempfile
echo "This script writes to temp file $tempfile
echo "This is the first line." >&3
echo "This is the last line." >&3
exec 3>&-

echo "Done creating temp file. The contents are:"
cat $tempfile 
rm -f $tempfile 2> /dev/null
wangsx@SC-201708020022:~/tmp$ sh test19
This script writes to temp file test19.fVVEwn
Done creating temp file. The contents are:
This is the first line.
This is the last line.

顯示的內(nèi)容大致如上地来,我的ubuntu子系統(tǒng)有點(diǎn)怪怪的,不知道為毛熙掺。

-t選項(xiàng)回強(qiáng)制mktemp命令在系統(tǒng)的臨時(shí)目錄來(lái)創(chuàng)建該文件靠抑,它會(huì)返回臨時(shí)文件的全路徑,而不是只有文件名适掰。

wangsx@SC-201708020022:~/tmp$ mktemp -t test20.XXXX
/tmp/test20.bY3Q
wangsx@SC-201708020022:~/tmp$ mktemp -t test20.XXXXXX
/tmp/test20.WrkAia

-d選項(xiàng)告訴mktemp創(chuàng)建一個(gè)臨時(shí)目錄而不是臨時(shí)文件颂碧。

記錄消息

有時(shí)候想將消息同時(shí)發(fā)送到顯示器和日志文件,用tee命令可以搞定类浪。

tee命令的功能就像一個(gè)T载城,它將從STDIN過(guò)來(lái)的數(shù)據(jù)同時(shí)發(fā)往兩處。一處是STDOUT费就,一處是tee命令行所指定的文件名诉瓦。

wangsx@SC-201708020022:~/tmp$ date | tee testfile
2017年 08月 22日 星期二 21:49:07 DST
wangsx@SC-201708020022:~/tmp$ cat testfile
2017年 08月 22日 星期二 21:49:07 DST

如果要追加文件,請(qǐng)使用-a選項(xiàng)。

實(shí)例

文件重定向常見于腳本需要讀入文件和輸出文件時(shí)睬澡。

下面是一個(gè)具體的實(shí)例:shell腳本使用命令行參數(shù)指定待讀取的.csv文件固额。.csv格式用于從電子表格中導(dǎo)出數(shù)據(jù),所以我們可以把數(shù)據(jù)庫(kù)數(shù)據(jù)放入電子表格煞聪,把電子表格保存成.csv格式斗躏,讀取文件,然后創(chuàng)建INSERT語(yǔ)句將數(shù)據(jù)插入MySQL數(shù)據(jù)庫(kù)昔脯。

#!/bin/bash
# read file and create INSERT statements for MySQL

outfile='members.sql'
IFS=","
while read lname fname address city state zip # read 使用IFS字符解析讀入的文本
do
    cat >> $outfile << EOF
    # >> 將cat的輸出追加到$outfile指定的文件中
    # cat的輸入不再取自于標(biāo)準(zhǔn)輸入啄糙,而是被重定向到腳本中存儲(chǔ)的數(shù)據(jù),EOF符號(hào)標(biāo)記了追加到文件中的數(shù)據(jù)的起止(兩個(gè))
    INSERT INTO members (lname,fname,address,city,state,zip) VALUES 
    ('$lname', '$fname', '$address', '$city', '$state', '$zip');
EOF
    # 上面是標(biāo)準(zhǔn)的SQL語(yǔ)句
done < $1 # 將命令行第一個(gè)參數(shù)指明的數(shù)據(jù)文件導(dǎo)入while

造一個(gè)符合的csv文件

wangsx@SC-201708020022:~/tmp$ cat members.csv
Blum,Richard,123 Main St.,Chicago,IL,60601
Blum,Barbara,123 Main St.,Chicago,IL,60601
Bresnahan,Timothy,456, Oak Ave.,Columbus,OH,43201

運(yùn)行腳本

wangsx@SC-201708020022:~/tmp$ ./test23 members.csv
wangsx@SC-201708020022:~/tmp$ cat members.sql
    INSERT INTO members (lname,fname,address,city,state,zip) VALUES
    ('Blum', 'Richard', '123 Main St.', 'Chicago', 'IL', '60601');
    INSERT INTO members (lname,fname,address,city,state,zip) VALUES
    ('Blum', 'Barbara', '123 Main St.', 'Chicago', 'IL', '60601');
    INSERT INTO members (lname,fname,address,city,state,zip) VALUES
    ('Bresnahan', 'Timothy', '456', ' Oak Ave.', 'Columbus', 'OH,43201');
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末云稚,一起剝皮案震驚了整個(gè)濱河市隧饼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌静陈,老刑警劉巖燕雁,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鲸拥,居然都是意外死亡贵白,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門崩泡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人猬膨,你說(shuō)我怎么就攤上這事角撞。” “怎么了勃痴?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵谒所,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我沛申,道長(zhǎng)劣领,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任铁材,我火速辦了婚禮尖淘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘著觉。我一直安慰自己村生,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布饼丘。 她就那樣靜靜地躺著趁桃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卫病,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天油啤,我揣著相機(jī)與錄音,去河邊找鬼蟀苛。 笑死益咬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的屹逛。 我是一名探鬼主播础废,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼罕模!你這毒婦竟也來(lái)了评腺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤淑掌,失蹤者是張志新(化名)和其女友劉穎蒿讥,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抛腕,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芋绸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了担敌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摔敛。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖全封,靈堂內(nèi)的尸體忽然破棺而出马昙,到底是詐尸還是另有隱情,我是刑警寧澤刹悴,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布行楞,位于F島的核電站,受9級(jí)特大地震影響土匀,放射性物質(zhì)發(fā)生泄漏子房。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一就轧、第九天 我趴在偏房一處隱蔽的房頂上張望证杭。 院中可真熱鬧慎璧,春花似錦盒犹、人聲如沸姑蓝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)可款。三九已至谆甜,卻和暖如春畦攘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背李茫。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工揭保, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人魄宏。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓秸侣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親宠互。 傳聞我的和親對(duì)象是個(gè)殘疾皇子味榛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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