第十五章:呈現(xiàn)數(shù)據(jù)
本章內(nèi)容
再探重定向
標(biāo)準(zhǔn)輸入和輸出
報告錯誤
丟棄錯誤
丟棄數(shù)據(jù)
創(chuàng)建日志文件
15.1 理解輸入和輸出
兩種顯示腳本輸出的方法
在顯示器屏幕上顯示輸出
將輸出重定向到文件中
15.1.1 標(biāo)準(zhǔn)文件描述符
Linux系統(tǒng)將每個對象當(dāng)做文件處理至会,這包括輸入和輸出進(jìn)程
Linux用文件描述符(file descriptor)來標(biāo)識每個文件對象
文件描述符是一個非負(fù)整數(shù),可以唯一標(biāo)識回話中打開的文件
每個進(jìn)程一次最多可以有九個文件描述符
出于特殊目的仔拟,bash shell保留了前三個文件描述符
Linux的標(biāo)準(zhǔn)文件描述符
文件描述符:縮寫:描述
0:STDIN:標(biāo)準(zhǔn)輸入
1:STDOUT:標(biāo)準(zhǔn)輸出
2:STDERR:標(biāo)準(zhǔn)錯誤
1.STDIN
STDIN文件描述符代表shell的標(biāo)準(zhǔn)輸入
對終端界面來說诵姜,標(biāo)準(zhǔn)輸入時鍵盤
shell從STDIN文件描述符對應(yīng)的鍵盤獲得輸入,在用戶輸入時處理每個字符
使用輸入重定向符號(<)時,讀取文件并能夠提取數(shù)據(jù)
使用cat命令用testfile文件中的行作為輸入
編寫testfile文件
This is first line.
This is a test line
This is third line.
執(zhí)行命令
cat < testfile
2.STDOUT
STDOUT文件描述符代表shell的標(biāo)準(zhǔn)輸出
在終端界面上工坊,標(biāo)準(zhǔn)輸出就是終端顯示器
shell的所有輸出會被定向到標(biāo)準(zhǔn)輸出中,也就是顯示器
默認(rèn)情況下敢订,大多數(shù)bash命令會將輸出導(dǎo)向STDOUT文件描述符
也可以使用輸出重定向來改變(>)
執(zhí)行命令
ls -l > test2
cat test2
who >> test2
cat test2
ls -al badfile > test3
cat test3
當(dāng)執(zhí)行一個錯誤的命令時王污,shell并未將錯誤消息重定向到文件中
3.STDERR
shell通過特殊字符的STDERR文件描述符來處理錯誤消息
STDERR文件描述符代表shell的標(biāo)準(zhǔn)錯誤輸出
shell或shell中運行的程序和腳本出錯時生成的錯誤消息都會發(fā)送到這個位置
默認(rèn)情況下,錯誤消息也會輸出到顯示器輸出中
STDERR并不會隨著STDOUT的重定向而發(fā)生改變
15.1.2 重定向錯誤
1.只重定向錯誤
STDERR文件描述符為2楚午,可以選擇只重定向錯誤消息
將文件描述符放在重定向符號前
該值必須緊緊地放在重定向符號前昭齐,否則不會生效
執(zhí)行命令
ls -al badfile 2> test4
cat test4
也可以組合使用STDOUT和STDERR
執(zhí)行命令
ls -la test badtest test2 2> test5
cat test5
2.重定向錯誤和數(shù)據(jù)
如果想重定向錯誤和正常輸出,必須用兩個重定向符號
需要在符號前面放上帶重定向數(shù)據(jù)所對應(yīng)的文件描述符
然后指向用于保持?jǐn)?shù)據(jù)的輸出文件
執(zhí)行命令
ls -al test test2 test3 badtest 2> test6 1>test7
cat test6
cat test7
使用特殊符號(&>)將STDOUT和STDERR的輸出重定向到同一個輸出文件
執(zhí)行命令
ls -al test test2 test3 badtest &>test7
cat test7
15.2 在腳本中重定向輸出
15.2.1 臨時重定向
命令演示:echo "This is an error message" >&2
命令說明:手動生成錯誤信息并輸出重定向到STDERR
編寫test8.sh腳本
#!/bin/bash
echo "This is an error" >&2
echo "This is normal output"
執(zhí)行命令
./test8.sh
./test8.sh 2>test9
cat test9
15.2.2 永久重定向
使用exec命令告訴shell在腳本執(zhí)行期間重定向某個特定文件描述符
編寫test10.sh腳本
#!/bin/bash
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"
執(zhí)行命令
./test10.sh
cat testout
也可以在腳本執(zhí)行過程中重定向STDOUT
編寫test11.sh腳本
#!/bin/bash
exec 2>testerror
echo "this is the start of the script"
echo "now redirecting all output to another location"
exec 1>testout
echo "Theis out should go to the testout file"
echo "but this should go to testerror file" >&2
執(zhí)行命令
./test11.sh
cat testout
cat testerror
15.3 在腳本中重定向輸入
命令演示:exec 0< testfile
命令說明:使用與腳本重定向STDOUT和STDERR相同的方法將STDIN從鍵盤重定向到其他位置
編寫test12.sh腳本
#!/bin/bash
exec 0< testfile
count=1
while read line
do
echo "Line #$count:$line"
count=$[ $count + 1 ]
done
15.4 創(chuàng)建自己的重定向
在腳本中重定向輸入和輸出時矾柜,并不局限這3個默認(rèn)的文件描述符
在shell中最多可以有9個打開的文件描述符
可以將其他6個從3~8的文件描述符中的任意一個分配給文件
15.4.1 創(chuàng)建輸出文件描述符
使用exec命令來給輸出分配文件描述符
編寫test13.sh腳本
#!/bin/bash
exec 3>test13out
echo "This should display on the monitor"
echo "and this should be stored in the file" >&3
echo "Then this should be back on the monitor"
執(zhí)行命令
./test13.sh
cat test13out
命令演示:exec 3>>test13out
命令說明:使用exec命令來講輸出追加到現(xiàn)有文件中
15.4.2 重定向文件描述符
在腳本中臨時重定向輸出阱驾,然后恢復(fù)默認(rèn)輸出設(shè)置
編寫test14.sh腳本
#!/bin/bash
exec 3>&1
exec 1>test14out
echo "This should store in the output file"
echo "along with whis line"
exec 1>&3
echo "Now things should be back normal"
執(zhí)行命令
./test14.sh
cat test14out
這個例子有點叫人抓狂就谜,來一段一段地看。首先里覆,腳本將文件描述符 3 重定向到文件描述符1
的當(dāng)前位置丧荐,也就是 STDOUT 。這意味著任何發(fā)送給文件描述符 3 的輸出都將出現(xiàn)在顯示器上喧枷。
第二個 exec 命令將 STDOUT 重定向到文件虹统,shell現(xiàn)在會將發(fā)送給 STDOUT 的輸出直接重定向到
輸出文件中。但是隧甚,文件描述符 3 仍然指向 STDOUT 原來的位置车荔,也就是顯示器。如果此時將輸出
數(shù)據(jù)發(fā)送給文件描述符 3 戚扳,它仍然會出現(xiàn)在顯示器上忧便,盡管 STDOUT 已經(jīng)被重定向了。
在向 STDOUT (現(xiàn)在指向一個文件)發(fā)送一些輸出之后咖城,腳本將 STDOUT 重定向到文件描述符
3 的當(dāng)前位置(現(xiàn)在仍然是顯示器)茬腿。這意味著現(xiàn)在 STDOUT 又指向了它原來的位置:顯示器。
這個方法可能有點叫人困惑宜雀,但這是一種在腳本中臨時重定向輸出切平,然后恢復(fù)默認(rèn)輸出設(shè)置
的常用方法。
15.4.3 創(chuàng)建輸入文件描述符
可以將STDIN文件描述符保存到另外一個文件描述符辐董,然后在讀取完文件之后再將STDIN恢復(fù)到它原來的位置
編寫test15.sh腳本
#!/bin/bash
exec 6<&0
exec 0< testfile
count=1
while read line
do
echo "Line #$count:$line"
count=$[ $count+1 ]
done
exec 0<&6
read -p "Are you done now [Y/N]?" answer
case $answer in
Y|y) echo "Goodbye" ;;
N|n) echo "Sorry,this is the end."
esac
15.4.4 創(chuàng)建讀寫文件描述符
可以用同一個文件描述符對同一個文件進(jìn)行讀寫
在對同一個文件進(jìn)行數(shù)據(jù)讀寫時悴品,shell會維護(hù)一個內(nèi)部指針
任何讀或?qū)懚紩闹羔樕洗蔚奈恢瞄_始
編寫test16.sh腳本
#!/bin/bash
exec 3<> testfile
read line <&3
echo "Read: $line"
echo "This is a test line" >&3
testfile內(nèi)容
This is the first line.
This is the second line.
This is the third line.
執(zhí)行命令
cat testfile
./test16.sh
cat testfile
15.4.5 關(guān)閉文件描述符
命令格式:exec 3>&-
命令說明:在腳本結(jié)束前手動關(guān)閉文件描述符,將它重定向到特殊符號&-
在關(guān)閉文件描述符時简烘,如果隨后在腳本中打開了同一個輸出文件苔严,則會覆蓋已有文件
編寫test17.sh腳本
#!/bin/bash
exec 3> test17file
echo "This is a test line of data" >&3
exec 3>&-
cat test17file
exec 3> test17file
echo "This'll be bad" >&3
執(zhí)行命令
./test17.sh
cat test17file
15.5 列出打開的文件描述符
使用lsof命令顯示已打開的文件描述符
編寫test18.sh腳本
#!/bin/bash
exec 3> test18file1
exec 6> test18file2
exec 7< testfile
/usr/bin/lsof -a -p $$ -d0,1,2,6,7
15.6 阻止命令輸出
可以將STDERR重定向到null文件的特殊文件
在Linux系統(tǒng)上null文件的標(biāo)準(zhǔn)位置時/dev/null
重定向到該位置的任何數(shù)據(jù)都會被丟掉
通常用于清除日志文件
命令演示:cat /dev/null > testfile
命令說明:清除testfile文件中的數(shù)據(jù)
15.7 創(chuàng)建臨時文件
15.7.1 創(chuàng)建本地臨時文件
命令演示:mktemp testing.XXXXXX
命令說明:mktemp命令創(chuàng)建一個臨時文件,會自動用6個字符碼替換這6個X孤澎,從而保證文件名在目錄中是唯一的届氢。且可以創(chuàng)建多個臨時文件,每個文件都是唯一的覆旭。
編寫test19.sh腳本
#!/bin/bash
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 second 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
執(zhí)行命令
./test19.sh
ls -al test19*
15.7.2 在/tmp目錄創(chuàng)建臨時文件
使用-t選項強(qiáng)制mktemp命令在系統(tǒng)的臨時目錄下創(chuàng)建該文件
mktemp命令會返回該臨時文件的全路徑
編寫test20.sh腳本
#!/bin/bash
tempfile=$(mktemp -t tmp.XXXXXX)
echo "This is a test file." > $tempfile
echo "This is the second line of the test." >> $tempfile
echo "The temp file is located at: $tempfile"
cat $tempfile
rm -f $tempfile
15.7.3 創(chuàng)建臨時目錄
使用-d選項告訴mktemp命令創(chuàng)建一個臨時目錄
編寫test21.sh腳本
#!/bin/bash
tempdir=$(mktemp -d dir.XXXXXX)
cd $tempdir
tempfile1=$(mktemp temp.XXXXXX)
tempfile2=$(mktemp temp.XXXXXX)
exec 7> $tempfile1
exec 8> $tempfile2
echo "Sending data to directory $tempdir"
echo "This is a test line of data for $tempfile1" >&7
echo "This is a test line of data for $tempfile2" >&8
執(zhí)行命令
./test21.sh
ls -al
ls -al dir.zKQTCL/
cat dir.zKQTCL/temp.EZBifQ
cat dir.zKQTCL/temp.sO4oa4
15.8 記錄消息
將輸出同時發(fā)送到顯示器和日志文件
使用tee命令退子,相當(dāng)于管道的一個T型接頭
將從STDIN過來的數(shù)據(jù)同時發(fā)往兩處
一處是STDOUT,另一處時tee命令所指定的文件名:tee filename
使用-a選項將數(shù)據(jù)追加到文件中型将,數(shù)據(jù)顯示在屏幕上的同時再永久保存在文件中
編寫test22.sh腳本
#!/bin/bash
tempfile=test22file
echo "This is the start of the test" | tee $tempfile
echo "This is the second line of the test" | tee -a $tempfile
echo "This is the end of the test" | tee -a $tempfile
執(zhí)行命令
./test22.sh
cat test22file
15.9 實例
案例說明:文件重定向常見于腳本需要讀入文件和輸出文件寂祥。通過讀取.csv格式的數(shù)據(jù)文件,輸出SQL INSERT語句來將數(shù)據(jù)插入數(shù)據(jù)庫
編寫members.csv文本
Blum,Richard,123 Main st.,Chicago,IL,60601
Blum,Barbara,123 Main st.,Chicago,IL,60601
Bresnahan,Christine,456 Oak Ave.,Columbus,OH,43201
Bresnahan,Timothy,456 Oak Ave.,Columbus,OH,43201
編寫test23.sh腳本
#!/bin/bash
outfile='members.sql'
IFS=','
while read lname fname address city state zip in ${1}
do
cat >> $outfile << EOF
INSERT INTO members (lname,fname,address,city,state,zip)
VALUES('$lname','$fname','$address','$city','$state','$zip');
EOF
done
執(zhí)行命令
./test23.sh < members.csv
cat members.sql
15.10 小結(jié)
bash shell允許在腳本中創(chuàng)建自己的文件描述符七兜。使用mktemp可以很方便的創(chuàng)建臨時目錄及文件丸凭。tee命令便于將輸出同時發(fā)送給標(biāo)準(zhǔn)輸出和日志文件。