說明:本文部分內(nèi)容均摘取自書籍《Linux命令行與shell腳本編程大全》婚瓜,版權(quán)歸原作者所有∨跏椋《Linux命令行與shell腳本編程大全》(第三版)第十五章學(xué)習(xí)總結(jié)
第十五章:呈現(xiàn)數(shù)據(jù)
本章內(nèi)容
再探重定向
標(biāo)準(zhǔn)輸入和輸出
報(bào)告錯(cuò)誤
丟棄錯(cuò)誤
丟棄數(shù)據(jù)
創(chuàng)建日志文件
15.1 理解輸入和輸出
兩種顯示腳本輸出的方法
在顯示器屏幕上顯示輸出
將輸出重定向到文件中
15.1.1 標(biāo)準(zhǔn)文件描述符
Linux系統(tǒng)將每個(gè)對(duì)象當(dāng)做文件處理,這包括輸入和輸出進(jìn)程
Linux用文件描述符(file descriptor)來標(biāo)識(shí)每個(gè)文件對(duì)象
文件描述符是一個(gè)非負(fù)整數(shù),可以唯一標(biāo)識(shí)回話中打開的文件
每個(gè)進(jìn)程一次最多可以有九個(gè)文件描述符
出于特殊目的,bash shell保留了前三個(gè)文件描述符
Linux的標(biāo)準(zhǔn)文件描述符
文件描述符:縮寫:描述
0:STDIN:標(biāo)準(zhǔn)輸入
1:STDOUT:標(biāo)準(zhǔn)輸出
2:STDERR:標(biāo)準(zhǔn)錯(cuò)誤
1.STDIN
STDIN文件描述符代表shell的標(biāo)準(zhǔn)輸入
對(duì)終端界面來說,標(biāo)準(zhǔn)輸入時(shí)鍵盤
shell從STDIN文件描述符對(duì)應(yīng)的鍵盤獲得輸入鸥跟,在用戶輸入時(shí)處理每個(gè)字符
使用輸入重定向符號(hào)(<)時(shí)等脂,讀取文件并能夠提取數(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的所有輸出會(huì)被定向到標(biāo)準(zhǔn)輸出中,也就是顯示器
默認(rèn)情況下耕皮,大多數(shù)bash命令會(huì)將輸出導(dǎo)向STDOUT文件描述符
也可以使用輸出重定向來改變(>)
執(zhí)行命令
ls -l > test2
cat test2
who >> test2
cat test2
ls -al badfile > test3
cat test3
當(dāng)執(zhí)行一個(gè)錯(cuò)誤的命令時(shí)苦锨,shell并未將錯(cuò)誤消息重定向到文件中
3.STDERR
shell通過特殊字符的STDERR文件描述符來處理錯(cuò)誤消息
STDERR文件描述符代表shell的標(biāo)準(zhǔn)錯(cuò)誤輸出
shell或shell中運(yùn)行的程序和腳本出錯(cuò)時(shí)生成的錯(cuò)誤消息都會(huì)發(fā)送到這個(gè)位置
默認(rèn)情況下氏仗,錯(cuò)誤消息也會(huì)輸出到顯示器輸出中
STDERR并不會(huì)隨著STDOUT的重定向而發(fā)生改變
15.1.2 重定向錯(cuò)誤
1.只重定向錯(cuò)誤
STDERR文件描述符為2,可以選擇只重定向錯(cuò)誤消息
將文件描述符放在重定向符號(hào)前
該值必須緊緊地放在重定向符號(hào)前仅胞,否則不會(huì)生效
執(zhí)行命令
ls -al badfile 2> test4
cat test4
也可以組合使用STDOUT和STDERR
執(zhí)行命令
ls -la test badtest test2 2> test5
cat test5
2.重定向錯(cuò)誤和數(shù)據(jù)
如果想重定向錯(cuò)誤和正常輸出,必須用兩個(gè)重定向符號(hào)
需要在符號(hào)前面放上帶重定向數(shù)據(jù)所對(duì)應(yīng)的文件描述符
然后指向用于保持?jǐn)?shù)據(jù)的輸出文件
執(zhí)行命令
ls -al test test2 test3 badtest 2> test6 1>test7
cat test6
cat test7
使用特殊符號(hào)(&>)將STDOUT和STDERR的輸出重定向到同一個(gè)輸出文件
執(zhí)行命令
ls -al test test2 test3 badtest &>test7
cat test7
15.2 在腳本中重定向輸出
15.2.1 臨時(shí)重定向
命令演示:echo "This is an error message" >&2
命令說明:手動(dòng)生成錯(cuò)誤信息并輸出重定向到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í)行期間重定向某個(gè)特定文件描述符
編寫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)建自己的重定向
在腳本中重定向輸入和輸出時(shí),并不局限這3個(gè)默認(rèn)的文件描述符
在shell中最多可以有9個(gè)打開的文件描述符
可以將其他6個(gè)從3~8的文件描述符中的任意一個(gè)分配給文件
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 重定向文件描述符
在腳本中臨時(shí)重定向輸出埃撵,然后恢復(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
這個(gè)例子有點(diǎn)叫人抓狂赵颅,來一段一段地看。首先暂刘,腳本將文件描述符 3 重定向到文件描述符1
的當(dāng)前位置饺谬,也就是 STDOUT 。這意味著任何發(fā)送給文件描述符 3 的輸出都將出現(xiàn)在顯示器上谣拣。
第二個(gè) exec 命令將 STDOUT 重定向到文件募寨,shell現(xiàn)在會(huì)將發(fā)送給 STDOUT 的輸出直接重定向到
輸出文件中。但是森缠,文件描述符 3 仍然指向 STDOUT 原來的位置拔鹰,也就是顯示器。如果此時(shí)將輸出
數(shù)據(jù)發(fā)送給文件描述符 3 辅鲸,它仍然會(huì)出現(xiàn)在顯示器上格郁,盡管 STDOUT 已經(jīng)被重定向了。
在向 STDOUT (現(xiàn)在指向一個(gè)文件)發(fā)送一些輸出之后独悴,腳本將 STDOUT 重定向到文件描述符
3 的當(dāng)前位置(現(xiàn)在仍然是顯示器)例书。這意味著現(xiàn)在 STDOUT 又指向了它原來的位置:顯示器。
這個(gè)方法可能有點(diǎn)叫人困惑刻炒,但這是一種在腳本中臨時(shí)重定向輸出决采,然后恢復(fù)默認(rèn)輸出設(shè)置
的常用方法。
15.4.3 創(chuàng)建輸入文件描述符
可以將STDIN文件描述符保存到另外一個(gè)文件描述符坟奥,然后在讀取完文件之后再將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)建讀寫文件描述符
可以用同一個(gè)文件描述符對(duì)同一個(gè)文件進(jìn)行讀寫
在對(duì)同一個(gè)文件進(jìn)行數(shù)據(jù)讀寫時(shí)树瞭,shell會(huì)維護(hù)一個(gè)內(nèi)部指針
任何讀或?qū)懚紩?huì)從指針上次的位置開始
編寫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é)束前手動(dòng)關(guān)閉文件描述符,將它重定向到特殊符號(hào)&-
在關(guān)閉文件描述符時(shí)爱谁,如果隨后在腳本中打開了同一個(gè)輸出文件晒喷,則會(huì)覆蓋已有文件
編寫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)位置時(shí)/dev/null
重定向到該位置的任何數(shù)據(jù)都會(huì)被丟掉
通常用于清除日志文件
命令演示:cat /dev/null > testfile
命令說明:清除testfile文件中的數(shù)據(jù)
15.7 創(chuàng)建臨時(shí)文件
15.7.1 創(chuàng)建本地臨時(shí)文件
命令演示:mktemp testing.XXXXXX
命令說明:mktemp命令創(chuàng)建一個(gè)臨時(shí)文件,會(huì)自動(dòng)用6個(gè)字符碼替換這6個(gè)X访敌,從而保證文件名在目錄中是唯一的凉敲。且可以創(chuàng)建多個(gè)臨時(shí)文件,每個(gè)文件都是唯一的寺旺。
編寫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)建臨時(shí)文件
使用-t選項(xiàng)強(qiáng)制mktemp命令在系統(tǒng)的臨時(shí)目錄下創(chuàng)建該文件
mktemp命令會(huì)返回該臨時(shí)文件的全路徑
編寫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)建臨時(shí)目錄
使用-d選項(xiàng)告訴mktemp命令創(chuàng)建一個(gè)臨時(shí)目錄
編寫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 記錄消息
將輸出同時(shí)發(fā)送到顯示器和日志文件
使用tee命令爷抓,相當(dāng)于管道的一個(gè)T型接頭
將從STDIN過來的數(shù)據(jù)同時(shí)發(fā)往兩處
一處是STDOUT,另一處時(shí)tee命令所指定的文件名:tee filename
使用-a選項(xiàng)將數(shù)據(jù)追加到文件中阻塑,數(shù)據(jù)顯示在屏幕上的同時(shí)再永久保存在文件中
編寫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 實(shí)例
案例說明:文件重定向常見于腳本需要讀入文件和輸出文件蓝撇。通過讀取.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)建臨時(shí)目錄及文件渤昌。tee命令便于將輸出同時(shí)發(fā)送給標(biāo)準(zhǔn)輸出和日志文件虽抄。