1. 程式人生 > >《Linux命令行與shell腳本編程大全》第十五章 呈現數據

《Linux命令行與shell腳本編程大全》第十五章 呈現數據

orm while 永久 date txt 沒有 電子 必須 document

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)仍然是標準輸出(屏幕)

《Linux命令行與shell腳本編程大全》第十五章 呈現數據