《Linux命令行与shell脚本编程大全》第十五章 呈现数据
15.1 理解輸入和輸出
現在知道兩種顯示腳本輸出的方法
1)在顯示器屏幕上顯示
2)將輸出文件重定向到文件中
15.1.1 標準文件描述符
Linux系統將每個對象當做文件處理。這包括輸入和數出進程。
Linux用文件描述符來標識每個文件對象。
它是一個非負整數,可以唯一標識會話中打開的文件。
每個進程一次最多可以有九個文件描述符
bash shell保留的前3個文件描述符(0、 1、 2)
?
1.STDIN 標準輸入(0)
STDIN文件代表shell的標準輸入。
對終端界面來說,標準輸入是鍵盤。
shell從STDIN文件描述符對應的鍵盤獲得輸入,在用戶輸入時處理每個字符
在使用輸入重定向符號( < )時,Linux會用重定向指定的文件來替換標準輸入文件描述符。它會讀取文件并提取數據,就如同它是鍵盤上鍵入的。
?
2.STDOUT 標準輸出(1)
STDOUT文件描述符代表shell的標準輸出。
對終端界面來說,標準輸出是終端顯示器。shell的所有輸出會被定向到標準輸出中。
也可以通過輸出重定向( > )來改變輸出。通過輸出重定向符號,可以將本來顯示在顯示器上的輸出重定向到指定的文件。
>>? 表示追加到文件
注意:用了輸出重定向,shell并未將錯誤消息重定向到輸出重定向文件中。錯誤消息仍會顯示在顯示器中。
?
3.STDERR 標準錯誤(2)
STDERR文件描述符來處理錯誤消息。
shell或shell中運行的程序和腳本出錯時生成的錯誤消息都會發送到這個位置。
默認情況下STROUT和STDERR指向同樣的地方(顯示器)。但是STDERR不會隨著STDOUT重定向而發生改變。
?
15.1.2 重定向錯誤
1.只重定向錯誤
將該文件描述符值(2)放在重定向符號(>)前面,必須挨著,不能有空格。
比如,查看一個不存在的文件:
$ls –al 2> log.txt
這種方法只會重定向錯誤消息,普通輸出不會被重定向。
?
2. 重定向錯誤和數據
需要用兩個重定向符號,需要在符號前面放上待重定向數據所對應的文件描述符,然后指定用于保存數據的輸出文件。
例如:
$ls -al test1 test2 test3 badfile 2> ErrLog.txt 1> DataLog.txt
表示將錯誤信息重定向到ErrLog.txt,正常輸出重定向到DataLog.txt。
這樣錯誤信息和正常輸出就分開在兩文件了。
?
$ls -al test1 test2 test3 badfile &> AllLog.txt
這樣表示將STDOUT和STDERR重定向到同一個文件AllLog.txt中了。
bash shell自動賦予了錯誤消息更高的優先級,這樣可以集中瀏覽錯誤信息了。
?
15.2 在腳本中重定向輸出
有兩種方法:
1)臨時重定向行輸出
2)永久重定向腳本中的所有命令
15.2.1 臨時重定向
可以單獨將一行重定向到STDERR。
比如:
echo “this is error msg” >&2
echo “this is normal msg”
?
正常運行不會看出什么,但是假如運行時重定向了STDERR就有意思了。
$./test 2> Error.txt
就可以看到第一行輸出到了 Error.txt。而正常輸出還是在屏幕上。
?
15.2.2 永久重定向
如果有大量數據需要重定向,那么就會比較麻煩。
新方法:用exec命令告訴shell在腳本執行期間重定向某個特定文件描述符
直接上例子:
1 #!/bin/bash
? 2 echo "this is error msg step1" >&2
? 3 echo "this is normal msg step1"
? 4 # 上面沒有重定向,所以還是在屏幕輸出。下面才開始重定向到需要的文件中
? 5 exec 1>test2log.txt
? 6 exec 2>test2Error.txt
? 7 echo "this is error msg step2" >&2
? 8 echo "this is normal msg step2"
這樣一旦重定向了就很難改回去了。
?
15.3 在腳本中重定向輸入
exec 命令允許你將STDIN重定向到Linux系統上的文件中。
例子:查看test2中的數據
? 1 #!/bin/bash
? 2 exec 0< test2 # 輸入重定向到test2中
? 3 echo "test2:"
? 4 count=1
? 5 while read line
? 6 do
? 7???????? echo "? $line"
? 8???????? count=$[ $count + 1 ]
? 9 done
?
15.4 創建自己的重定向
之前說一個進程最多可以與9個打開的文件描述符。其他6個(3 ~ 8)的文件描述符均可用作輸入或輸出重定向。
可以將這些文件描述符中的任意一個分配給文件。
15.4.1 創建輸出文件描述符
用exec命令給輸出分配文件描述符。
和標準的文件描述符一樣,一旦將另一個文件描述符分配給了一個文件,這個重定向就會一直有效,直到你重新分配。
例子:
? 1 #!/bin/bash
? 2 exec 3>test4log.txt # exec 3>>test4log.txt 這個是將輸出追加到現有文件
? 3 echo "This is Normal msg"
? 4 echo "This is fd:3 msg" >&3
?
15.4.2 重定向文件描述符
現在介紹怎么恢復已重定向的文件描述符。
可以分配另外一個文件描述符給標準文件描述符,反之亦然。
可以將STDOUT重定向到另外一個文件描述符,然后再利用該文件描述符重定向回STDOUT
例子:
? 1 #!/bin/bash
? 2 # storing STDOUT, then coming back to it
? 3 exec 3>&1 # 3重定向到STDOUT。意味著給3的數據都將出現再顯示器上
? 4 exec 1>test5log.txt # 將STDOUT重定向到文件。但是3仍然指向STDOUT原來的位置,也就是顯示器。這時給3發會顯示在顯示器中。給STDOUT發會顯示在文件中
? 5 echo "This should store in the output file"
? 6 echo "alone with this line."
? 7
? 8 exec 1>&3 # 將STDOUT重定向到3的當前位置(也就是顯示器)
? 9 echo "now things should be back to normal"
?
15.4.3 創建輸入文件描述符
跟上面類似,先將STDIN保存到另外一個文件描述符,然后讀取完文件在將STDIN恢復
例子:
? 1 #!/bin/bash
? 2 exec 6<&0 # 6先保存STDIN的位置
? 3 exec 0<test5 # 將STDIN重定向到 test5
? 4 count=1
? 5 while read line
? 6 do
? 7???????? echo "? $line"
? 8???????? count=$[ $count +1 ]
? 9 done
?10
?11 exec 0<&6 # 讀取完成后將STDIN重定向到文件描述符6,從而恢復之前的位置
?12 read -p "Are you done now?" answer
?13 case $answer in
?14 Y|y) echo "GoodBye!!!";;
?15 N|n) echo "Sorry, this is the end";;
?16 *) echo "Error End";;
?17 esac
?
15.4.4 創建讀寫文件描述符
可以打開單個文件描述符作為輸入和輸出。可以利用同一個文件描述符對同一個文件進行讀寫。
用起來要小心:由于是對同一個文件進行數據讀寫,shell會維護一個內部指針,指明在文件中的當前位置。任何讀或寫都是從文件指針上次的位置開始。
例子:
1 #!/bin/bash
? 2 exec 3<> testfile
? 3 read line <&3
? 4 echo "Read:$line" #注意這里寫是從文件指針上次的位置開始,也就是讀了一行之后的位置
? 5 echo "Write: This is test line" >&3
?
15.4.5 關閉文件描述符
如果你創建了新的輸入或輸出文件描述符,shell會在腳本退出時自動關閉它們。
但是某些時候還是要自己去關閉。
如何關閉: 將要關閉的文件描述符重定向到特殊符號 &-
一旦關閉后,就不能在腳本中向他寫入數據,否則shell會產生錯誤信息。
例子:
? 1 #!/bin/bash
? 2 # close fd test
? 3 exec 3>test8log.txt
? 4 echo "This is normal to fd:3" >&3
? 5 exec 3>&-
? 6 echo "after close write:his is normal to fd:3" >&3 # 關閉后再往里面寫會出錯
? 7
? 8 exec 3>test8log.txt # 這里相當于重新打開了
? 9 echo "This is bad normal to fd:3" >&3 # 會覆蓋原來的
?
15.5 列出打開的文件描述符
lsof命令會列出整個linux系統打開的所有的文件描述符。會產生大量輸出。
還可以接選項和參數:
-p 后面接要查看的進程。? $$ 表示當前進程
-d 后面指定要顯示的文件描述符編號。
例子:
? 1 #!/bin/bash
? 2 exec 3> testfile
? 3 lsof -a -p $$ -d 0,1,2,3,4
?
15.6 阻止命令輸出
有時不想顯示腳本的輸出。可以將輸出重定向到一個叫做null文件的特殊文件中去。
比如:
$ls –al > /dev/null
還可以這樣清空日志文件
$ cat /dev/null > TestLog.txt
?
?
15.7 創建臨時文件
linux使用/tmp目錄來存放不需要永久保留的文件。大部分linux發行版配置了系統在啟動時自動刪除/tmp目錄下的所有文件。
系統上的任何用戶賬戶都有權限在讀寫/tmp目錄中的文件。
mktemp可以在/tmp目錄中創建一個唯一的臨時文件。一旦創建了文件,你就在腳本中有了完整的讀寫權限,別人無法訪問它。
15.7.1 創建本地臨時文件
只需要指定一個文件名模板就行了,在文件末尾加上6個X。
$mktemp testing.XXXXXX
注意:這里一定要有大寫的X。這里的X有點通配符的意思。還可以寫不是X的
mktemp命令的輸出是它所創建的文件的名字。在腳本中保存起來,就能在后面的腳本里引用了。
例子:
? 1 #!/bin/bash
? 2 # create and using temp file
? 3 tempfile=$(mktemp test10.XXXXXX)
? 4 echo "tempfile = $tempfile"
? 5 exec 3>$tempfile
? 6 echo "This script writes to tmp file $tempfile"
? 7 echo "this is first line" >&3
? 8 echo "this is second line" >&3
? 9 echo "this is third line" >&3
?10 exec 3>&-
?11
?12 echo? "Now delete file $tempfile"
?13 rm -f $tempfile > /dev/null
?
15.7.2 在/tmp目錄創建臨時文件
-t 選項會強制mktemp在系統的臨時目錄來創建該文件。
這個時候返回用來創建臨時文件的全路徑,而不是只有文件名。
就上面的例子加上 –t就好了。
。。。
tempfile=$(mktemp -t test10.XXXXXX)
。。。
?
15.7.3 創建臨時目錄
-d選項用來創建臨時目錄。這樣就能用改目錄進行任何需要的操作了。
例子:
? 1 #!/bin/bash
? 2 # create and using temp dir
? 3 tempdir=$(mktemp -d test12dir.12XXXX)
? 4 cd $tempdir
? 5 echo This in Dir:$(pwd)
? 6 tempfile=$(mktemp test12.XXXXXX)
? 7 echo "tempfile = $tempfile"
? 8 exec 3>$tempfile
? 9 echo "This script writes to tmp file $tempfile"
?10 echo "this is first line" >&3
?11 echo "this is second line" >&3
?12 echo "this is third line" >&3
?
15.8 記錄消息
將輸出同時發送到顯示器和日志文件,需要特殊命令tee就可以了。
tee命令相當于管道第一個T型接頭。它將STDIN過來的數據同時發往兩處,一處是STDOUT,一處是指定的文件。
比如:
$date | tee log.txt
$date | tee –a log.txt?? # 這個是將數據追加到文件中
例子:
? 1 #!/bin/bash
? 2 # tee test
? 3 echo "This is 1 msg" | tee test13log.txt
? 4 echo "This is 2 msg" | tee -a test13log.txt
? 5 echo "This is 3 msg" | tee -a test13log.txt
?
15.9 實例
文件重定向常見于腳本需要讀入文件和輸出文件時。
需求:把數據數據放入電子表格中(.csv文件),讀取文件,創建INSERT語句。
例子:
? 1 #!/bin/bash
? 2 outfile='members.sql'
? 3 IFS=,
? 4 while read name age sex num
? 5 do
? 6???????? cat >> $outfile << EOF
? 7???????? insert into members (name, age, sex, num) values('$name', '$age', '$sex', '$num');
? 8 EOF
? 9 done <${1}
1)${1}代表第一個命令行參數。它指明了待讀取數據的文件。
2)read會用IFS字符解析讀入的文本,我們在這里將IFS指定為逗號。
?
cat >> $outfile << EOF? // 這一段還是不大理解
這個包含一個輸出追加重定向(>>)和一個輸入追加重定向(<<)。
>> 將cat命令的輸出追加到由$outfile變量指定的文件中。
cat命令的輸入不在取自標準輸入,而是被重定向到腳本中存儲的數據。
EOF符號標記了追加到文件中的數據的起止。
?
輸入文件 + 運行 + 結果:
?
說明:
特殊重定向(here document):
command << delimiter
???????? document
delimiter
作用是將兩個delimiter之間的內容(document)作為輸入傳給command
注意:結尾的delimiter一定要頂格寫,不能有空格。
(1)
? 6???????? cat >> $outfile << EOF
? 7???????? insert into members (name, age, sex, num) values('$name', '$age', '$sex', '$num');
? 8 EOF
(2)
? 6???????? cat << EOF
? 7???????? insert into members (name, age, sex, num) values('$name', '$age', '$sex', '$num');
? 8 EOF
?
黃色高亮部分作為輸入傳給cat。(1)重定向到outfile去了,(2)仍然是標準輸出(屏幕)
轉載于:https://www.cnblogs.com/xcywt/p/7912037.html
總結
以上是生活随笔為你收集整理的《Linux命令行与shell脚本编程大全》第十五章 呈现数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis Cluster日常操作命令梳
- 下一篇: 如何访问 Service?- 每天5分钟