Linux Shell 用法(一)3.文件描述符與重定向

一、文件描述符與重定向

編寫腳本的時候會頻繁用到標準輸入(stdin)、標準輸出(stdout)和標準錯誤 (stderr)。腳本可以使用大於號將輸出重定向到文件中。命令產生的文本可能是正常輸出,也
可能是錯誤信息。默認情況下,正常輸出(stdout)和錯誤信息(stderr)都會顯示在屏幕上。 我們可以分別爲其指定特定的文件描述符來區分兩者。
文件描述符是與某個打開的文件或數據流相關聯的整數。文件描述符0、1以及2是系統預留的。
 0 ——stdin (標準輸入)。
 1 —— stdout(標準輸出)。
 2 —— stderr(標準錯誤)。

  1. 使用大於號將文本保存到文件中:
    該命令會將輸出的文本保存在temp.txt中。如果temp.txt已經存在,大於號會清空該文件中 先前的內容。
$ echo "This is a sample text 1" > temp.txt

2.使用雙大於號將文本追加到文件中:

$ echo "This is sample text 2" >> temp.txt

3.使用cat查看文件內容:

 $ cat temp.txt

This is sample text 1
This is sample text 2

接着來看看如何重定向stderr。當命令產生錯誤信息時,該信息會被輸出到stderr流。考 慮下面的例子:

 $ ls +

ls: cannot access +: No such file or directory
這裏,+是一個非法參數,因此會返回錯誤信息

4.成功和不成功的命令
當一個命令發生錯誤並退回時,它會返回一個非0的退出狀態;而當命令成 功完成後,它會返回爲0的退出狀態。退出狀態可以從特殊變量$?中獲得(在命 令結束之後立刻運行echo $?,就可以打印出退出狀態)。

下面的命令會將stderr文本打印到屏幕上,而不是文件中(因爲stdout並沒有輸出,所以 out.txt的內容爲空):

  $ ls + > out.txt

ls: cannot access +: No such file or directory

在下面的命令中,我們使用2>(數字2以及大於號)將stderr重定向到out.txt:

$ ls + 2> out.txt #沒有問題

你可以將stderr和stdout分別重定向到不同的文件中:

 $ cmd 2>stderr.txt 1>stdout.txt

5.下面這種更好的方法能夠將stderr轉換成stdout,使得stderr和stdout都被重定向到同 一個文件中:

$ cmd 2>&1 alloutput.txt
或者這樣
$ cmd &> output.txt

如果你不想看到或保存錯誤信息,那麼可以將stderr的輸出重定向到/dev/null

假設我們有3個文件,分別是a1、a2、a3。但是普通用戶對文件a1沒有“讀 -寫-執行”權限。如果需要打印文件名以a起始的所有文件的內容,可以使用cat命令。來設置 一些測試文件:

$ echo A1 > a1
$ echo A2 > a2
$ echo A3 > a3
$ chmod 000 a1 #清除所有權限

使用通配符(a*)顯示這些文件內容的話,系統會顯示出錯信息,因爲文件a1沒有可讀權限: $ cat a*
cat: a1: Permission denied
A2
A3
其中,cat: a1: Permission denied屬於stderr信息。我們可以將其重定向到一個文件中, 同時將stdout信息發送到終端。

$ cat a* 2> err.txt # stderr被重定向到err.txt 

A2
A3

$ cat err.txt

cat: a1: Permission denied
我們在處理一些命令輸出的同時還想將其保存下來,以備後用。
stdout作爲單數據流 (single stream),可以被重定向到文件或是通過管道傳入其他程序,但是無法兩者兼得。
6.有一種方法既可以將數據重定向到文件,還可以提供一份重定向數據的副本作爲管道中後續 命令的stdin。tee命令從stdin中讀取,然後將輸入數據重定向到stdout以及一個或多個文件中。
command | tee FILE1 FILE2 | otherCommand
在下面的代碼中,tee命令接收到來自stdin的數據。它將stdout的一份副本寫入文件 out.txt,同時將另一份副本作爲後續命令的stdin。命令cat -n爲從stdin中接收到的每一行數 據前加上行號並將其寫入stdout:

$ cat a* | tee out.txt | cat -n

cat: a1: Permission denied
1 A2
2 A3
使用cat查看out.txt的內容:

$ cat out.txt

A2
A3
注意,cat: a1: Permission denied 並沒有在文件內容中出現,因爲 這些信息被髮送到了stderr,而tee只能從stdin中讀取。
默認情況下,tee命令會將文件覆蓋,但它提供了一個-a選項,可用於追加內容。 $ cat a* | tee -a out.txt | cat –n
帶有參數的命令可以寫成:command FILE1 FILE2 …,或者就簡單地使用command FILE。
要發送輸入內容的兩份副本給stdout,使用-作爲命令的文件名參數即可:

`$ cmd1 | cmd2 | cmd -`

例如:

$ echo who is this | tee -

who is this
who is this
也可以將/dev/stdin作爲輸出文件名來代替stdin。類似地,使用/dev/stderr代表標準錯誤, /dev/stdout代表標準輸出。這些特殊的設備文件分別對應stdin、stderr和stdout。

7.重定向操作符(>和>>)可以將輸出發送到文件中,而不是終端。>和>>略有差異。儘管兩 者都可以將文本重定向到文件,但是前者會先清空文件,然後再寫入內容,而後者會將內容追加 到現有文件的尾部。默認情況下,重定向操作針對的是標準輸出。如果想使用特定的文件描述符,你必須將描述 符編號置於操作符之前。>等同於1>;對於>>來說,情況也類似(即>>等同於1>>)。處理錯誤時,來自stderr的輸出被傾倒入文件/dev/null中。./dev/null是一個特殊的設備文件,它會丟棄接收到的任何數據。null設備通常也被稱爲黑洞,因爲凡是進入其中的數據都將一去不返。

8.從stdin讀取輸入的命令能以多種方式接收數據。可以用cat和管道來指定我們自己的文件:
考慮下面的例子:

 $ cat file | cmd
 $ cmd1 | cmd2

(1). 將文件重定向到命令 藉助小於號(<),我們可以像使用stdin那樣從文件中讀取數據:

$ cmd < file

(2). 重定向腳本內部的文本塊 可以將腳本中的文本重定向到文件。要想將一條警告信息添加到自動生成的文件頂部,可以
使用下面的代碼:

#!/bin/bash
cat<<EOF>log.txt

This is a generated file. Do not edit. Changes will be overwritten.
EOF
出現在cat <log.txt與下一個EOF行之間的所有文本行都會被當作stdin數據。 log.txt文件的內容顯示如下:

$ cat log.txt
 This is a generated file. Do not edit. Changes will be overwritten.
  1. 自定義文件描述符
    文件描述符是一種用於訪問文件的抽象指示器(abstract indicator)。存取文件離不開被稱爲
    “文件描述符”的特殊數字。0、1和2分別是stdin、stdout和stderr預留的描述符編號。 exec命令創建全新的文件描述符。如果你熟悉其他編程語言中的文件操作,那麼應該對文
    件打開模式也不陌生。常用的打開模式有3種。
     只讀模式。
     追加寫入模式。
     截斷寫入模式。
    <操作符可以將文件讀入stdin。>操作符用於截斷模式的文件寫入(數據在目標文件內容被 截斷之後寫入)。>>操作符用於追加模式的文件寫入(數據被追加到文件的現有內容之後,而且 該目標文件中原有的內容不會丟失)。文件描述符可以用以上3種模式中的任意一種來創建。
    創建一個用於讀取文件的文件描述符:
$ exec 3<input.txt #使用文件描述符3打開並讀取文件

我們可以這樣使用它:

$ echo this is a test line > input.txt
$ exec 3<input.txt

現在你就可以在命令中使用文件描述符3了。例如:

$ cat<&3

this is a test line
如果要再次讀取,我們就不能繼續使用文件描述符3了,而是需要用exec重新創建一個新的 文件描述符(可以是4)來從另一個文件中讀取或是重新讀取上一個文件。
創建一個用於寫入(截斷模式)的文件描述符:

 $ exec 4>output.txt   #打開文件進行寫入

例如:

$ exec 4>output.txt
$ echo newline >&4
$ cat output.txt
newline

#打開文件進行寫入
創建一個用於寫入(追加模式)的文件描述符:

$ exec 5>>input.txt

例如:

$ exec 5>>input.txt
$ echo appended line >&5
$ cat input.txt

newline
appended line 9

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