天天看點

《Linux指令行與shell腳本程式設計大全》第十五章 呈現資料15.1 了解輸入和輸出

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指令給輸出配置設定檔案描述符。

和标準的檔案描述符一樣,一旦将另一個檔案描述符配置設定給了一個檔案,這個重定向就會一直有效,直到你重新配置設定。

例子:

  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

  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恢複

  2 exec 6<&0 # 6先儲存STDIN的位置

  3 exec 0<test5 # 将STDIN重定向到 test5

  8         count=$[ $count +1 ]

 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會維護一個内部指針,指明在檔案中的目前位置。任何讀或寫都是從檔案指針上次的位置開始。

  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會産生錯誤資訊。

  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 # 關閉後再往裡面寫會出錯

  8 exec 3>test8log.txt # 這裡相當于重新打開了

  9 echo "This is bad normal to fd:3" >&3 # 會覆寫原來的

15.5 列出打開的檔案描述符

lsof指令會列出整個linux系統打開的所有的檔案描述符。會産生大量輸出。

還可以接選項和參數:

-p 後面接要檢視的程序。  $$ 表示目前程序

-d 後面指定要顯示的檔案描述符編号。

  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指令的輸出是它所建立的檔案的名字。在腳本中儲存起來,就能在後面的腳本裡引用了。

  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選項用來建立臨時目錄。這樣就能用改目錄進行任何需要的操作了。

  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   # 這個是将資料追加到檔案中

  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語句。

  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符号标記了追加到檔案中的資料的起止。

輸入檔案 + 運作 + 結果:

《Linux指令行與shell腳本程式設計大全》第十五章 呈現資料15.1 了解輸入和輸出

說明:

特殊重定向(here document):

command << delimiter

         document

delimiter

作用是将兩個delimiter之間的内容(document)作為輸入傳給command

注意:結尾的delimiter一定要頂格寫,不能有空格。

(1)

(2)

  6         cat << EOF

黃色高亮部分作為輸入傳給cat。(1)重定向到outfile去了,(2)仍然是标準輸出(螢幕)

繼續閱讀