LINUX與UNIX SHELL編程指南--(5)shell輸入與輸出 管道

shell的輸入與輸出

在shell腳步中,可以用幾種不同的方式讀取數據:可以使用標準輸入--缺省爲鍵盤,或者指定一個文件作爲輸入。

同樣,對於輸出,如果不指定某個文件作爲輸出,標準輸出總是和終端屏幕相關聯。

 

--echo

使用echo命令可以顯示文本行或者變量,或者把字符串輸入到文件。

它的一般形式爲:

echo string

echo命令有很多功能,其中最常用的有:

\c 不換行

\t  跳格 

\n 換行  

 

 linux中使用“-n”選項來禁止echo命令輸出後換行:

 # echo -n "what name: "
必須使用-e選項才能使轉義符生效:

echo -e "what name: \t luyx \n"

如果想把一個字符串輸出到文件中,使用重定向符合>  :

echo "The log files have all been done">myfile

如何把雙引號包含到e c h o命令的字符串中。引號是一個特殊字符,所以必須要使用反斜槓\來使s h e l l忽略它的特殊含義。假設你希望使用echo命令輸出這樣的字符串:“/dev/rmt0”,那麼我們只要在引號前面加上反斜槓\即可:

echo "\"/dev/rmt0"\"       結果顯示爲:"/dev/rmt0"

 

--read

可以使用read語句從鍵盤或文件的某一行文本中讀入信息,並將其賦值給一個變量。

如果只指定一個變量,那麼read將會把所有的輸入賦給該變量,直到遇到第一個文件結束符或者回車。

read的一般形式:

read varible1 varible2 .....

下面的例子中,只指定一個變量,它將被賦予直至回車之前的所有內容

 [root@localhost ~]# read name
Hello I am superman
[root@localhost ~]# echo $name
Hello I am superman

 

下面的例子中,我們給出了兩個變量,它們分別被賦予名字和姓氏。s h e l l將用空格作爲變量之間的分隔符:

 [root@localhost ~]# read name surname
yongxin lu
[root@localhost ~]# echo $name $surname
yongxin lu

 

如果輸入文本域過長, Shell 將所有的超長部分賦予最後一個變量。下面的例子,假定要讀取變量名字和姓,但這次輸入三個名字;
[root@localhost ~]# read name surname
John Lemon doe
[root@localhost ~]# echo $name
John
[root@localhost ~]# echo $surname
Lemon doe

在上面的例子中,如果我們輸入字符串John Lemon Doe,那麼第一個單詞將被賦給第一個變量,而由於變量數少於單詞數,字符串後面的部分將被全部賦給第二個變量

 

在編寫s h e l l腳本的時候,如果擔心用戶會對此感到迷惑,可以採用每一個r e a d語句只給一
個變量賦值的辦法:

[root@localhost ~]# vi test.sh
#
echo -e "fisrt name:\c"
read name
echo -e "Middle name:\c"
read middle
echo -e "last name:\c"
read surname

--cat

c a t是一個簡單而通用的命令,可以用它來顯示文件內容,創建文件,還可以用它來顯示
控制字符。在使用c a t命令時要注意,它不會在文件分頁符處停下來;它會一下顯示完整個文
件。如果希望每次顯示一頁,可以使用m o r e命令或把c a t命令的輸出通過管道傳遞到另外一個
具有分頁功能的命令中,請看下面的例子:

$cat myfiel | more

cat命令的一般形式爲:
cat [options] filename1 ... filename2 ...
cat命令最有用的選項就是:
-v 顯示控制字符


如果希望顯示名爲myfile的文件,可以用:
$ cat myfile
如果希望顯示myfile1、myfile2、myfile3這三個文件,可以用:
$ cat myfile1 myfile2 myfile3
如果希望創建一個名爲big file的文件,該文件包含上述三個文件的內容,可以把上面命令
的輸出重定向到新文件中:
$ cat myfile1 myfile2 myfile3 > bigfile

如果希望創建一個新文件,並向其中輸入一些內容,只需使用c a t命令把標準輸出重定向到該文件中,這時c a t命令的輸入是標準輸入—鍵盤,你輸入一些文字,輸入完畢後按< C T R L - D >結束輸入。這真是一個非常簡單的文字編輯器!

[root@localhost ~]# cat > myfile
Hello world

< C T R L - D >

 

有一點要提醒的是,如果在敲入了c a t以後就直接按回車,該命令會等你輸入字符。如果你本來就是要輸入一些字符,那麼它除了會在你輸入時在屏幕上顯示以外,還會再回顯這些內容;最後按< C T R L - D >結束輸入即可。

[root@localhost ~]# cat
my name
my name
luyx
luyx

 

--管道

可以通過管道把一個命令的輸出傳遞給另一個命令作爲輸入。管道用豎槓|表示。它的一
般形式爲:
命令1 |命令2
其中|是管道符號。

 

在下面的例子中,在當前目錄中執行文件列表操作,如果沒有管道的話,所有文件就會顯示出來。當s h e l l看到管道符號以後,就會把所有列出的文件交給管道右邊的命令,因此管道的含義正如它的名字所暗示的那樣:把信息從一端傳送到另外一端。在這個例子中,接下來g r e p命令在文件列表中搜索myfile:

[root@localhost ~]# ls |grep myfile
myfile

 

s e d、a w k和g r e p都很適合用管道,特別是在簡單的一行命令中。在下面的例子中, w h o命
令的輸出通過管道傳遞給a w k命令,以便只顯示用戶名和所在的終端。

[root@localhost ~]# who
root     tty1         Mar 14 15:35
root     pts/0        Mar 15 07:10 (192.168.50.1)
root     pts/2        Mar 15 08:33 (192.168.50.1)
[root@localhost ~]# who | awk '{print $1 "\t"$2}'
root    tty1
root    pts/0
root    pts/2

 

--tee

 t e e命令作用可以用字母T來形象地表示。它把輸出的一個副本輸送到標準輸出,另一個副本拷貝到相應的文件中。如果希望在看到輸出的同時,也將其存入一個文件,那麼這個命令再合適不過了。
它的一般形式爲:
tee -a files
其中,- a表示追加到文件末尾。

 [root@localhost ~]# who |tee who.out
root     tty1         Mar 14 15:35
root     pts/0        Mar 15 07:10 (192.168.50.1)
root     pts/2        Mar 15 08:33 (192.168.50.1)
[root@localhost ~]# cat who.out
root     tty1         Mar 14 15:35
root     pts/0        Mar 15 07:10 (192.168.50.1)
root     pts/2        Mar 15 08:33 (192.168.50.1)


 

標準輸入、輸出和錯誤
當我們在s h e l l中執行命令的時候,每個進程都和三個打開的文件相聯繫,並使用文件描述符來引用這些文件。由於文件描述符不容易記憶, s h e l l同時也給出了相應的文件名。
下面就是這些文件描述符及它們通常所對應的文件名:

------------
文件                  文件描述符
輸入文件        —   標準輸入0
輸出文件        —   標準輸出1
錯誤輸出文件   —  標準錯誤2

------------
系統中實際上有1 2個文件描述符,但是正如我們在上表中所看到的, 0、1、2是標準輸入、輸出和錯誤。可以任意使用文件描述符3到9。
 標準輸入
標準輸入是文件描述符0。它是命令的輸入,缺省是鍵盤,也可以是文件或其他命令的輸出。
 標準輸出
標準輸出是文件描述符1。它是命令的輸出,缺省是屏幕,也可以是文件。
標準錯誤
標準錯誤是文件描述符2。這是命令錯誤的輸出,缺省是屏幕,同樣也可以是文件。

你可能會問,爲什麼會有一個專門針對錯誤的特殊文件?這是由於很多人喜歡把錯誤單獨保存到一個文件中,特別是在處理大的數據文件時,可能會產生很多錯誤。如果沒有特別指定文件說明符,命令將使用缺省的文件說明符(你的屏幕,更確切地說是你的終端)。

 

--文件重定向
在執行命令時,可以指定命令的標準輸入、輸出和錯誤,要實現這一點就需要使用文件重定向。表5 - 1列出了最常用的重定向組合,並給出了相應的文件描述符。在對標準錯誤進行重定向時,必須要使用文件描述符,但是對於標準輸入和輸出來說,這不是必需的。爲了完整起見,我們在表5 - 1中列出了兩種方法。

表5-1 常用文件重定向命令
command > filename         把把標準輸出重定向到一個新文件中                                                        
command >> filename       把把標準輸出重定向到一個文件中(追加)                                                    
command 1 > fielname      把把標準輸出重定向到一個文件中                                                           
command > filename 2>&1 把把標準輸出和標準錯誤一起重定向到一個文件中                                         
command 2 > filename      把把標準錯誤重定向到一個文件中                                                           
command 2 >> filename    把把標準輸出重定向到一個文件中(追加)                                                   
command >> filename 2>&1 把把標準輸出和標準錯誤一起重定向到一個文件中(追加)                              
command < filename >filename2 把command命令以filename文件作爲標準輸入,以filename2文作爲標準輸出
command < filename               把c o m m a n d命令以f i l e n a m e文件作爲標準輸入                       
command << delimiter             把從標準輸入中讀入,直至遇到d e l i m i t e r分界符                           
command <&m                       把把文件描述符m作爲標準輸入                                                      
command >&m                       把把標準輸出重定向到文件描述符m中                                               
command <&-                        把關閉標準輸入                   
                                                     

 

 重定向標準輸出
讓我們來看一個標準輸出的例子。在下面的命令中,把/etc/passwd文件中的用戶I D域按照用戶命排列。該命令的輸出重定向到sort.out文件中。要提醒注意的是,在使用sort命令的時候(或其他含有相似輸入文件參數的命令),重定向符號一定要離開sort命令兩個空格,否則該命令會把它當作輸入文件。
$ cat passwd | awk -F: '{print $1}' | sort  1>sort.out
從表5 - 1中可以看出,我們也可以使用如下的表達方式,結果和上面一樣:
$ cat passwd | awk -F: '{print $1}' | sort   >sort.out

 

如果希望追加到已有的文件中(在該文件不存在的情況下創建該文件),那麼可以使用> > f i l e n a m e:

[root@localhost ~]# pwd >>pwd.out

 

重定向標準輸入
可以指定命令的標準輸入。在a w k一章就會遇到這樣的情況。下面給出一個這樣的例子:
$ sort < name.txt
在上面的命令中, s o r t命令的輸入是採用重定向的方式給出的,不過也可以直接把相應的
文件作爲該命令的參數:
$ sort name.txt
在上面的例子中,還可以更進一步地通過重定向爲s o r t命令指定一個輸出文件n a m e . o u t。這樣屏幕上將不會出現任何信息(除了錯誤信息以外):
$ sort <name.txt >name.out
在發送郵件時,可以用重定向的方法發送一個文件中的內容。在下面的例子中,用戶l o u i s e將收到一個郵件,其中含有文件c o n t e n t s . t x t中的內容:
$ mail louise < contents.txt

 

重定向操作符command << delimiter是一種非常有用的命令,通常都被稱爲“此處”文擋。

現在只介紹它的功能。shell將分界符delimiter之後直至下一個同樣的分界符之前的所有內容都作爲輸入,遇到下一個

可以任意定義分界符delimiter,最常見的是EoF

[root@localhost ~]# cat >>myfile <<EOF
> hell there i am using a $TERM termina
> EOF

[root@localhost ~]# cat myfile
there i am using a vt100 termina

 

重定向標準錯誤
爲了重定向標準錯誤,可以指定文件描述符2。讓我們先來看一個例子,因爲舉例子往往會讓人更容易明白。在這個例子中, g r e p命令在文件m i s s i l e s中搜索t r i d e n t字符串:

[root@localhost ~]# grep "luyx" missiles
grep: missiles: No such file or directory

g r e p命令沒有找到該文件,缺省地向終端輸出了一個錯誤信息。現在讓我們把錯誤重定向到文件 /dev/null 中(實際就上是系統的垃圾箱):
[root@localhost ~]# grep "luyx" missiles 2>/dev/null
[root@localhost ~]#

這樣所有的錯誤輸出都輸送到了/ d e v / n u l l,不再出現在屏幕上。
如果你在對更重要的文件進行操作,可能會希望保存相應的錯誤。下面就是一個這樣的
例子,這一次錯誤被保存到g r e p . e r r文件中:

[root@localhost ~]# grep "luyx" missiles 2>grep.err
[root@localhost ~]# cat grep.err
grep: missiles: No such file or directory

 

還可以把錯誤追加到一個文件中。在使用一組命令完成同一個任務時,這種方法非常有用。在下面的例子中,兩個g r e p命令把錯誤都輸出到同一個文件中;由於我們使用了> >符號進行追加,後面一個命令的錯誤(如果有的話)不會覆蓋前一個命令的錯誤。

 [root@localhost ~]# grep "luyx" missiles 2>grep.err
[root@localhost ~]# grep "root" missiles 2>grep.err


結合使用標準輸出和標準錯誤
一個快速發現錯誤的方法就是,先將輸出重定向到一個文件中,然後再把標準錯誤重定向到另外一個文件中。下面給出一個例子:我有兩個審計文件,其中一個的確存在,而且包含一些信息,而另一個由於某種原因已經不存在了(但我不知道)。我想把這兩個文件合併到a c c o u n t s . o u t文件中。
$ cat account_qtr.doc account_end.doc 1>accounts.out 2>accounts.err
現在如果出現了錯誤,相應的錯誤將會保存在a c c o u n t s . e r r文件中。

 

合併標準輸出和標準錯誤
在合併標準輸出和標準錯誤的時候,切記s h e l l是從左至右分析相應的命令的。下面給出一個例子:
$ cleanup >cleanup.out 2>&1
在上面的例子中,我們將c l e a n u p腳本的輸出重定向到c l e a n u p . o u t文件中,而且其錯誤也被重定向到相同的文件中。
$ grep "standard"* > grep.out 2>&1
在上面的例子中, g r e p命令的標準輸出和標準錯誤都被重定向到g r e p . o u t文件中

 

================

有關tee/重定向/標準錯誤輸出這些使用,在《shell 重定向的深入》 中涉及到了。

我當初在學重定向深入的時候,早把這篇中的有關知識給忘記了,再次說明覆習總結的重要性。不過很長時間不用確實也難免有忘記的部分2011年07月12日 - 流口水的小豬 - 軌跡

有關read命令,在逐行讀取文件時有使用到。

 

=====再做補充===========


1. 標準輸入與輸出
我們知道,執行一個shell命令行時通常會自動打開三個標準文件,即標準輸入文件(stdin),通常對應終端的鍵盤;標準輸出文件(stdout)和標準錯誤輸出文件(stderr),這兩個文件都對應終端的屏幕。進程將從標準輸入文件中得到輸入數據,將正常輸出數據輸出到標準輸出文件,而將錯誤信息送到標準錯誤文件中。
我們以cat命令爲例,cat命令的功能是從命令行給出的文件中讀取數據,並將這些數據直接送到標準輸出。若使用如下命令:
$ cat config
將會把文件config的內容依次顯示到屏幕上。但是,如果cat的命令行中沒有參數,它就會從標準輸入中讀取數據,並將其送到標準輸出。例如:

$ cat
Hello world
Hello world
Bye
Bye
$
用戶輸入的每一行都立刻被cat命令輸出到屏幕上。

另一個例子,命令sort按行讀入文件正文(當命令行中沒有給出文件名時,表示從標準輸入讀入),將其排序,並將結果送到標準輸出。下面的例子是從標準輸入讀入一個採購單,並將其排序。
$ sort
bananas
carrots
apples
apples
bananas
carrots
$

這時我們在屏幕上得到了已排序的採購單。直接使用標準輸入/輸出文件存在以下問題:
輸入數據從終端輸入時,用戶費了半天勁輸入的數據只能用一次。下次再想用這些數據時就得重新輸入。而且在終端上輸入時,若輸入有誤修改起來不是很方便。
輸出到終端屏幕上的信息只能看不能動。我們無法對此輸出作更多處理,如將輸出作爲另一命令的輸入進行進一步的處理等。
爲了解決上述問題,Linux系統爲輸入、輸出的傳送引入了另外兩種機制,即輸入/輸出重定向和管道。

輸入重定向

輸入重定向是指把命令(或可執行程序)的標準輸入重定向到指定的文件中。也就是說,輸入可以不來自鍵盤,而來自一個指定的文件。所以說,輸入重定向主要用於改變一個命令的輸入源,特別是改變那些需要大量輸入的輸入源。
例如,命令wc統計指定文件包含的行數、單詞數和字符數。如果僅在命令行上鍵入:
$ wc
wc將等待用戶告訴它統計什麼,這時shell就好象死了一樣,從鍵盤鍵入的所有文本都出現在屏幕上,但並沒有什麼結果,直至按下<ctrl+d>,wc纔將命令結果寫在屏幕上。
如果給出一個文件名作爲wc命令的參數,如下例所示,wc將返回該文件所包含的行數、單詞數和字符數。
$ wc /etc/passwd
20 23 726 /etc/passwd
$

另一種把/etc/passwd文件內容傳給wc命令的方法是重定向wc的輸入。輸入重定向的一般形式爲:命令<文件名。可以用下面的命令把wc命令的輸入重定向爲/etc/passwd文件:
$ wc < /etc/passwd
20 23 726
$

另一種輸入重定向稱爲here文檔,它告訴shell當前命令的標準輸入來自命令行。here文檔的重定向操作符使用<<。它將一對分隔符(本例中用delim表示)之間的正文重定向輸入給命令。下例將一對分隔符delim之間的正文作爲wc命令的輸入,統計出正文的行數、單詞數和字符數。
$ wc<
>this text forms the content
>of the here document,which
>continues until the end of
>text delimter
>delim
4 17 98

在<<操作符後面,任何字符都可以作爲正文開始前的分隔符,本例中使用delim作爲分隔符。here文檔的正文一直延續到遇見另一個分隔符爲止。第二個分隔符應出現在新行的開頭。這時here文檔的正文(不包括開始和結束的分隔符)將重新定向送給命令wc作爲它的標準輸入。
由於大多數命令都以參數的形式在命令行上指定輸入文件的文件名,所以輸入重定向並不經常使用。儘管如此,當要使用一個不接受文件名作爲輸入參數的命令,而需要的輸入內容又存在一個文件裏時,就能用輸入重定向解決問題。輸出重定向

輸出重定向

是指把命令(或可執行程序)的標準輸出或標準錯誤輸出重新定向到指定文件中。這樣,該命令的輸出就不顯示在屏幕上,而是寫入到指定文件中。
輸出重定向比輸入重定向更常用,很多情況下都可以使用這種功能。例如,如果某個命令的輸出很多,在屏幕上不能完全顯示,那麼將輸出重定向到一個文件中,然後再用文本編輯器打開這個文件,就可以查看輸出信息;如果想保存一個命令的輸出,也可以使用這種方法。還有,輸出重定向可以用於把一個命令的輸出當作另一個命令的輸入(還有一種更簡單的方法,就是使用管道,將在下面介紹)。
輸出重定向的一般形式爲:命令>文件名。例如:
$ ls > directory.out
$ cat directory.out
ch1.doc ch2.doc ch3.doc chimp config mail/ test/
$

將ls命令的輸出保存爲一個名爲directory.out的文件。
注:如果>符號後邊的文件已存在,那麼這個文件將被重寫。

爲避免輸出重定向中指定文件只能存放當前命令的輸出重定向的內容,shell提供了輸出重定向的一種追加手段。輸出追加重定向與輸出重定向的功能非常相似,區別僅在於輸出追加重定向的功能是把命令(或可執行程序)的輸出結果追加到指定文件的最後,而該文件原有內容不被破壞。
如果要將一條命令的輸出結果追加到指定文件的後面,可以使用追加重定向操作符>>。形式爲:命令>>文件名。例如:
$ ls *.doc>>directory.out
$ cat directory.out
ch1.doc ch2.doc ch3.doc chimp config mail/ test/
ch1.doc ch2.doc ch3.doc
$

和程序的標準輸出重定向一樣,程序的錯誤輸出也可以重新定向。使用符號2>(或追加符號2>>)表示對錯誤輸出設備重定向。例如下面的命令:
$ ls /usr/tmp 2> err.file
可在屏幕上看到程序的正常輸出結果,但又將程序的任何錯誤信息送到文件err.file中,以備將來檢查用。
還可以使用另一個輸出重定向操作符(&>)將標準輸出和錯誤輸出同時送到同一文件中。例如:
$ ls /usr/tmp &> output.file

利用重定向將命令組合在一起,可實現系統單個命令不能提供的新功能。例如使用下面的命令序列:
$ ls /usr/bin > /tmp/dir
$ wc –w < /tmp/dir
459
統計了/usr/bin目錄下的文件個數。

管 道
將一個程序或命令的輸出作爲另一個程序或命令的輸入,有兩種方法,一種是通過一個臨時文件將兩個命令或程序結合在一起,例如上個例子中的/tmp/dir文件將ls和wc命令聯在一起;另一種是Linux所提供的管道功能。這種方法比前一種方法更好。
管道可以把一系列命令連接起來,這意味着第一個命令的輸出會作爲第二個命令的輸入通過管道傳給第二個命令,第二個命令的輸出又會作爲第三個命令的輸入,以此類推。顯示在屏幕上的是管道行中最後一個命令的輸出(如果命令行中未使用輸出重定向)。
通過使用管道符“|”來建立一個管道行。用管道重寫上面的例子:
$ ls /usr/bin|wc -w
1789

再如:
$ cat sample.txt|grep "High"|wc -l

管道將cat命令(列出一個文件的內容)的輸出送給grep命令。grep命令在輸入裏查找單詞High,grep命令的輸出則是所有包含單詞High的行,這個輸出又被送給wc命令,wc命令統計出輸入中的行數。假設sample.txt文件的內容如下:

Things to do today:
Low:Go grocery shopping
High:Return movie
High:Clear level 3 in Alien vs. Predator
Medium:Pick up clothes from dry cleaner
那麼該管道行的結果是2。

命令替換

命令替換和重定向有些相似,但區別在於命令替換是將一個命令的輸出作爲另外一個命令的參數。常用命令格式爲:
command1 `command2`
其中,command2的輸出將作爲command1的參數。需要注意的是這裏的`符號,被它括起來的內容將作爲命令執行,執行後的結果作爲command1的參數。例如:
$ cd `pwd`
該命令將pwd命令列出的目錄作爲cd命令的參數,結果仍然是停留在當前目錄下。

發佈了26 篇原創文章 · 獲贊 6 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章