本章內(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)方法:
-
只重定向錯(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ò)誤信息锈死。
-
重定向錯(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');