bash >& - 在shell中,“2>&1”是什麼意思?




&1 nohup (13)

我在重定向中發現了這篇精彩的文章: 所有關於重定向的內容

將標準輸出和標準錯誤重定向到一個文件

$ command&>文件

這一行代碼使用&>操作符將兩個輸出流(stdout和stderr)從命令重定向到文件。 這是bash快速將兩個流重定向到同一目的地的快捷方式。

以下是在bash重定向兩個流之後文件描述符表的外觀:

正如你可以看到stdout和stderr現在都指向文件。 所以寫入stdout和stderr的任何東西都會寫入文件。

有兩種方法可以將兩個流重定向到同一個目標。 您可以逐個重定向每個流:

$ command> file 2>&1

這是將兩個流重定向到文件的更常見方式。 首先將stdout重定向到文件,然後將stderr複製為與stdout相同。 所以兩個流最終都指向文件。

當bash看到多個重定向時,它會從左向右處理它們。 我們來看看這些步驟,看看會發生什麼。 在運行任何命令之前,bash的文件描述符表如下所示:

現在bash處理第一個重定向>文件。 我們之前已經看到了這一點,它使stdout指向文件:

下一個bash會看到第二個重定向2>&1。 我們之前沒有看到過這個重定向。 這一個複製文件描述符2作為文件描述符1的一個副本,我們得到:

兩個流都被重定向到文件。

不過要小心! 寫作:

命令>文件2>&1

與寫作不一樣:

$ command 2>&1>文件

重定向的順序在bash中很重要! 該命令僅將標準輸出重定向到文件。 stderr仍然會打印到終端。 要了解為什麼發生這種情況,我們再來一遍。 所以在運行命令之前,文件描述符表如下所示:

現在bash處理重定向從左到右。 它首先看到2>&1,因此它將stderr複製到標準輸出。 文件描述符表變為:

現在bash看到第二個重定向>文件,它將stdout重定向到文件:

你看到這裡發生了什麼? 標準輸出現在指向文件,但stderr仍然指向終端! 所有寫入stderr的東西仍然會打印到屏幕上! 所以對於重定向的順序要非常小心!

還要注意,在bash中,寫下這個:

$ command&>文件

與以下內容完全相同:

$命令>&文件

在Unix shell中,如果我想將stderrstdout組合到stdout流中進行進一步操作,我可以在命令結尾附加以下內容:

2>&1

所以,如果我想在g ++的輸出中使用“head”,我可以這樣做:

g++ lots_of_errors 2>&1 | head

所以我只能看到前幾個錯誤。

我總是無法記住這一點,而且我經常不得不去查看它,主要是因為我沒有完全理解這個特殊技巧的語法。 有人可以分解這個並且逐字解釋什麼是“2>&1”嗎?


人們總是記得paxdiablo關於重定向目標的當前位置的暗示......這重要。

我對2>&1運算符的個人助記符是這樣的:

  • 想像&意義'and''add' (角色是一個陰謀 - 而且 ,不是嗎?)
  • 所以它變成: '重定向2 (stderr)到1 (stdout)已經/當前所在的位置,並添加兩個流'

同樣的助記符也適用於其他常用的重定向, 1>&2

  • 想想&意義and或者add ...(你知道和號是的,是的?)
  • 所以它變成: '重定向1 (標準輸出)到2 (stderr)已經/當前所在的位置,並添加兩個流'

並且永遠記住:您必須從右向左讀取重定向鏈“從末到尾”( 而不是從左到右)。


重定向輸入

輸入的重定向會導致文件描述符n的文本描述符n將被打開以讀取字的擴展名,如果未指定n,則輸入標準輸入(文件描述符0)。

重定向輸入的一般格式是:

      [n]<word

重定向輸出

輸出的重定向會導致文件的名稱由單詞的擴展名開始寫入文件描述符n,如果未指定n,則標準輸出(文件描述符1)。 如果文件不存在,則創建該文件; 如果它確實存在,則它被截斷為零大小。

重定向輸出的一般格式是:

      [n]>word

移動文件描述符

移動文件描述符重定向操作符

      [n]<&digit-

如果未指定n,則將文件描述符數字移至文件描述符n或標準輸入(文件描述符0)。 數字複製到n後關閉。

同樣,重定向操作符

      [n]>&digit-

如果未指定n,則將文件描述符數字移動到文件描述符n或標準輸出(文件描述符1)。

參考:

man bash
鍵入/^REDIRECT以定位到redirection部分,了解更多..

在線版本在這裡:
http://www.gnu.org/software/bash/manual/bashref.html#Redirections

PS:

很多時候, man是學習linux的強大工具


該構造將標準錯誤流( stderr )發送到標準輸出( stdout )的當前位置 - 此貨幣問題似乎被其他答案忽略了。

您可以使用此方法將任何輸出句柄重定向到另一個輸出句柄,但它通常用於將stdoutstderr流引導到單個流中進行處理。

一些例子是:

# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR

# Run the less pager without stderr screwing up the output.
foo 2>&1 | less

# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile

# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2

請注意,最後一個不會stderr指向outfile2它會將它重定向到參數遇到時的stdoutoutfile1 ), 然後stdout重定向到outfile2

這允許一些非常複雜的欺騙。


0表示輸入,1表示標準輸出,2表示標準錯誤。

一個提示somecmd >1.txt 2>&1是正確的,而somecmd 2>&1 >1.txt是完全錯誤的沒有效果!


2是控制台標準錯誤。

1是控制台標準輸出。

這是標準的Unix,Windows也遵循POSIX。 例如,當你跑步

perl test.pl 2>&1

標準錯誤被重定向到標準輸出,所以你可以看到兩個輸出在一起。

perl test.pl > debug.log 2>&1

執行後,您可以在debug.log中看到所有輸出,包括錯誤。

perl test.pl 1>out.log 2>err.log

然後標準輸出到out.log,標準錯誤到err.log。

我建議你試著去理解這些。


文件描述符1是標準輸出(標準輸出)。
文件描述符2是標準錯誤(stderr)。

這裡有一種方法來記住這個構造(儘管它不完全準確):首先, 2>1可能看起來是將stderr重定向到stdout的一種好方法。 但是,它實際上會被解釋為“將stderr重定向到名為1的文件”。 &表示接下來是文件描述符而不是文件名。 所以構造變成: 2>&1


這就像將錯誤壓縮到標準輸出或終端一樣。 即。 cmd不是命令$ cmd 2> filename cat filename命令未找到

發送到文件的錯誤就像發送到終端的2>&1錯誤那樣


假設你的系統中不存在/foo ,並且/tmp確實......

$ ls -l /tmp /foo

將打印/tmp的內容並打印/foo的錯誤消息

$ ls -l /tmp /foo > /dev/null

會將/tmp的內容髮送到/dev/null並打印/foo的錯誤消息

$ ls -l /tmp /foo 1> /dev/null

將完全相同(注意1

$ ls -l /tmp /foo 2> /dev/null

將打印/tmp的內容並將錯誤消息發送到/dev/null

$ ls -l /tmp /foo 1> /dev/null 2> /dev/null

將發送列表以及錯誤消息到/dev/null

$ ls -l /tmp /foo > /dev/null 2> &1

是速記


2>&1是一個POSIX shell構造。 這裡是一個細分,按令牌標記:

2 :“ 標準錯誤 ”輸出文件描述符。

>&複製輸出文件描述符運算符( 輸出重定向運算符>的變體)。 給定[x]>&[y] ,將由x表示的文件描述符設為輸出文件描述符y的副本。

1標準輸出 ”輸出文件描述符。

表達式2>&1文件描述符2>&1複製到位置2 ,因此執行環境中寫入2 (“標準錯誤”)的任何輸出將轉到原來由1 (“標準輸出”)描述的同一文件。

進一步解釋:

文件描述符 :“每進程唯一的非負整數,用於標識用於文件訪問目的的打開文件。”

標準輸出/錯誤 :請參閱shell文檔Redirection部分中的以下註釋:

打開的文件由從零開始的十進制數表示。 最大的可能值是實現定義的; 但是,所有實現應支持至少0到9(包含),供應用程序使用。 這些數字被稱為“文件描述符”。 值0,1和2具有特殊意義和常規用途,並且由某些重定向操作暗示; 它們分別被稱為標準輸入,標準輸出和標準錯誤。 程序通常從標準輸入中獲取輸入,並在標準輸出中寫入輸出。 錯誤消息通常寫在標準錯誤上。 重定向操作符可以在前面加上一個或多個數字(不允許插入字符)來指定文件描述符編號。


要回答你的問題:它會將任何錯誤輸出(通常發送到stderr)並將其寫入標準輸出(stdout)。

當你需要對所有輸出進行分頁時,這是有用的,例如“更多”。 一些程序將打印使用信息打印到stderr中。

幫助你記住

  • 1 =標準輸出(程序打印正常輸出)
  • 2 =標準錯誤(程序打印錯誤)

“2>&1”只是將發送到stderr的所有內容都指向標準輸出。

我也推薦閱讀這篇文章,在錯誤重定向的地方詳細介紹這個主題。


關於重定向的一些技巧

關於這個的一些語法特性可能具有重要的行為。 有一些關於重定向, STDERRSTDOUT和參數排序的小樣本。

1 - 覆蓋或追加?

符號>意味著重定向

  • >表示將整個完整文件發送 ,覆蓋目標(如果存在)(請參閱#3後面的noclobber bash功能)。
  • >>意指如果存在,除了追加到目標外。

無論如何,如果文件不存在,文件將被創建。

2 - shell命令行依賴於順序!

為了測試這個,我們需要一個簡單的命令來發送兩個輸出

$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

(當然,你沒有一個名為/tnt的目錄)。 那麼,我們有它!

所以讓我們看看:

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1

$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory

最後一個命令行將STDERR轉儲到控制台,它似乎不是預期的行為...但是...

如果您想對一個輸出進行一些後期過濾 ,則可以使用另一個或兩個輸入:

$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'

$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->

請注意,本段中的最後一條命令行與之前的paraghaph中的命令行完全相同,在這裡我寫的看起來並不是預期的行為 (因此,這甚至可能是預期的行為)。

那麼有一些關於重定向的技巧, 在兩個輸出上做不同的操作

$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2  2>&1  | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan  7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory

注意: &9描述符會自發發生,因為) 9>&2

附錄:nota! 使用新版本的bash ( >4.0 ),有一個新功能和更具性感的語法來完成這種事情:

$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory

最後是這樣的級聯輸出格式:

$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
     1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

附錄:nota! 相同的新語法,兩種方式:

$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
     1  O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

STDOUT通過一個特定的過濾器, STDERR到另一個,最後兩個輸出合併通過第三個命令過濾器。

3 - 關於noclobber選項和>| 句法

這是關於覆蓋

set -o noclobber指示bash 覆蓋任何現有文件, >| 語法讓你通過這個限制:

$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:15 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:19 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:21 CET 2013

每次都會覆蓋文件,現在就是:

$ set -o noclobber

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

通過>|

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

取消設置此選項和/或詢問是否已設置。

$ set -o | grep noclobber
noclobber           on

$ set +o noclobber

$ set -o | grep noclobber
noclobber           off

$ date > $testfile ; cat $testfile
Mon Jan  7 13:24:27 CET 2013

$ rm $testfile

4 - 最後一招和更多...

為了重定向給定命令的輸出,我們看到正確的語法可能是:

$ ls -ld /tmp /tnt >/dev/null 2>&1

對於這種特殊情況,有一個快捷語法: &> ...或>&

$ ls -ld /tmp /tnt &>/dev/null 

$ ls -ld /tmp /tnt >&/dev/null 

注意:如果2>&1存在, 1>&2也是一個正確的語法:

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

4b-現在,我會讓你考慮一下:

$ ls -ld /tmp /tnt 2>&1 1>&2  | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

$ ls -ld /tmp /tnt 1>&2 2>&1  | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

4c-如果您對更多信息感興趣

你可以點擊閱讀精細手冊:

man -Len -Pless\ +/^REDIRECTION bash

在bash控制台中;-)


實時,用戶和系統進程時間統計

其中一件事情不像另一件事。 真實指的是實際經過的時間; 用戶和系統是指僅由進程使用的CPU時間

  • 實時是從通話開始到結束的掛鐘時間。 這是所有已用時間,包括其他進程使用的時間片和進程花費的時間(例如,如果它正在等待I / O完成)。

  • 用戶是進程用戶模式代碼(內核以外)所花費的CPU時間。 這只是執行過程中使用的實際CPU時間。 該過程花費的其他過程和時間被阻止不計入此數字。

  • Sys是進程中內核中CPU時間的數量。 這意味著在內核中執行CPU時間花費在系統調用中,而不是仍然在用戶空間中運行的庫代碼。 像'用戶'一樣,這只是進程使用的CPU時間。 請參閱下面的內核模式(也稱為'supervisor'模式)和系統調用機制的簡要說明。

User+Sys會告訴你你的進程使用了多少實際的CPU時間。 請注意,這是跨越所有CPU,因此如果進程有多個線程(並且此進程在具有多個處理器的計算機上運行),它可能會超過Real報告的掛鐘時間(通常會發生這種情況)。 請注意,在輸出中,這些數字包括所有子進程(及其後代)的UserSys時間以及它們可能已經被收集的時間,例如wait(2)waitpid(2) ,但底層系統調用返回流程及其子女的統計數據。

統計time (1)報告的起源time (1)

time報告的統計數據來自各種系統調用。 '用戶'和'Sys'來自wait (2)times (2) ,具體取決於特定的系統。 '真實'是從gettimeofday (2)調用收集的開始和結束時間計算得出的。 取決於系統的版本,各種其他統計數據(例如上下文切換的數量)也可以按time收集。

在多處理器計算機上,多線程進程或分叉子進程的時間可能會比總CPU時間少 - 因為不同的線程或進程可能並行運行。 此外,所報告的時間統計來自不同的起源,因此,對於非常短的運行任務記錄的時間可能會受到舍入誤差的影響,正如原始海報給出的示例所示。

關於內核與用戶模式的簡短介紹

在Unix或任何受保護的內存操作系統上, “內核”或“超級用戶”模式指的是CPU可以運行的特權模式 。某些可能影響安全性或穩定性的特權操作只能在CPU運行時這種模式; 這些操作不適用於應用程序代碼。 這種行為的一個例子可能是操縱MMU以訪問另一個進程的地址空間。 通常情況下, user-mode代碼不能這樣做(有充分的理由),儘管它可以從內核請求共享內存 ,而內核可以由多個進程讀取或寫入。 在這種情況下,通過安全機制從內核明確請求共享內存,並且這兩個進程必須明確附加到內核才能使用它。

特權模式通常被稱為“內核”模式,因為內核由在此模式下運行的CPU執行。 為了切換到內核模式,你必鬚髮出一個特定的指令(通常稱為trap ),將CPU切換到在內核模式下運行, 並運行跳轉表中特定位置的代碼。 出於安全原因,您不能切換到內核模式並執行任意代碼 - 通過一個無法寫入的地址表來管理陷阱,除非CPU以超級用戶模式運行。 你用一個明確的陷阱編號進行陷阱,並在跳轉表中查找地址; 內核擁有有限數量的受控入口點。

C庫中的“系統”調用(特別是man手冊第2部分中描述的那些調用)具有用戶模式組件,這是您實際從C程序調用的組件。 在幕後,他們可能會向內核發出一個或多個系統調用來執行諸如I / O之類的特定服務,但他們仍然具有以用戶模式運行的代碼。 如果需要,也可以直接從任何用戶空間代碼直接向內核模式發出陷阱,儘管您可能需要編寫彙編語言片段來為呼叫正確設置寄存器。 描述Linux內核提供的系統調用的頁面和設置寄存器的約定可以在here.找到here.

更多關於'sys'

有些東西是您的代碼無法在用戶模式下執行的 - 例如分配內存或訪問硬件(HDD,網絡等)。 這些都在內核的監督之下,而且它本身就可以做到。 你所做的一些操作(比如malloc或者fread / fwrite )將會調用這些內核函數,然後這些函數將被視為'sys'時間。 不幸的是,它並不像“每次調用malloc都會計入'sys'時間”那樣簡單。 對malloc的調用會自己做一些處理(仍然以'user'計算),然後在某個地方它可能會調用內核中的函數(以'sys'時間計算)。 從內核調用返回後,'user'中會有更多時間,然後malloc將返回到您的代碼。 至於什麼時候發生切換,以及它在內核模式中花費了多少......你不能說。 這取決於圖書館的實施情況。 另外,其他看起來很無辜的函數也可能在後台使用malloc等等,然後在'sys'中再次有一些時間。





bash shell unix redirect