簡體   English   中英

在Unix / Linux shell編程中:>和>&之間的區別

[英]In the Unix/Linux shell programming:the difference between > and >&

int main(void)
{

  char buf[] = "standard err, output.\n";

  printf("standard output.\n");

  if (write(STDERR_FILENO,buf, 22) != 22)
      printf("write err!\n");

  exit(0);
}

編譯使用:

gcc -Wall text.c

然后在外殼中運行:

  1. ./a.out > outfile 2 >& 1

    結果:outfile的內容是:

     standard err, output. standard output. 
  2. ./a.out 2 >& 1 >outfile

    結果:

    這首先打印到終端: standard err, output.
    和outfile的內容是: standard output.

問題:

  • 我想問一下2 >& fd2 > file之間的區別。
    它們都等於函數dup()嗎?

  • 另一個問題:為何超出文件內容:

      standard err, output. standard output. 

    我期望outfile的內容為:

      standard output. standard err, output 

實際上,在bash中, >&dup2非常相似。 也就是說,應用了文件描述符的文件描述符將與右邊的描述符引用相同的文件。 所以:

$ ./a.out > outfile 2>& 1

它將stdout(1)重定向到文件outfile ,然后,dup2 stderr(2)引用與stdout(1)相同的文件。 也就是說,stdout和stderr都被重定向到該文件。

$ ./a.out 2>& 1 >outfile

它將重定向stderr(2)引用與stdout(1)相同的文件,即控制台,然后,將重定向stdout(1)引用文件outfile 也就是說,stderr將輸出到控制台,並將stdout輸出到文件。

而這正是您所得到的。

范式混合


盡管有理由故意做所有這些事情,但是作為一種學習經驗,在我可能稱之為“域邊界”的地方混合使用操作可能會造成混亂。

緩沖與非緩沖I / O

printf()被緩沖, write()是直接系統調用。 無論如何寫操作都會立即發生,當輸出是終端時,printf將(通常)逐行緩沖,而當輸出是真實文件時,則逐塊緩沖。 在文件輸出的情況下(重定向),只有當您從main()返回或以其他方式調用exit(3)時,才會發生實際的printf輸出,除非您打印了一堆東西。

歷史性的csh重定向vs bash重定向

比爾·喬伊(Bill Joy)在UCB編寫的現在已經被遺忘的(但通常仍是默認安裝的)csh,而一名研究生則擁有一些不錯的功能,這些功能已導入到廚房水槽外殼中,或者與所有外殼功能一起想到。 是的,我在這里談論bash。 因此,在csh中,重定向標准輸出和標准錯誤的方法只是說cmd>&file ,這實際上比“官方” Bourne shell提供的工具包方法更加文明。 但是,伯恩(Bourne)語法在其他地方有其優點,無論如何,它仍然是占主導地位的范例。

但是,bash的“本機”重定向功能有些復雜,盡管其他功能似乎已經有了良好的開端,但我不會嘗試在SO答案中對其進行總結。 無論如何,您在一個測試中使用了真正的bash重定向,而bash在另一個測試中也使用了傳統的csh語法,並且該程序本身混合了范例。 從shell的角度來看,主要問題是重定向順序在bash樣式語法中非常重要,而csh樣式語法僅指定最終結果。

2>&1部分使外殼程序執行以下操作:

dup2(1, 2);

這使fd 2成為fd 1的“副本”。

2> file被解釋為

fd = open(file, ...);
dup2(fd, 2);

這將打開一個文件,並將filedescriptor放入插槽2。

這里有幾個松散相關的問題。

樣式注釋:我建議使用2>&1不帶空格。 我什至沒有意識到間隔版本會起作用(我懷疑它在80年代中期沒有在Bourne外殼中使用),而壓縮版本是編寫它的傳統方法。

文件描述符I / O重定向符號在C shell及其衍生版本中並非全部可用; 它們可以在Bourne外殼及其衍生物(Korn外殼,POSIX外殼,Bash等)中使用。

shell必須要做的就是>file2>file2>&1之間的區別。 前兩個安排將寫到文件描述符的輸出(第一種情況,即標准輸出; 2情況下,即標准錯誤)輸出到命名文件。 這意味着程序寫入標准輸出的所有內容都將保存到文件中。 第三個符號將2(標准錯誤)安排為與1(標准輸出)相同的文件描述符; 寫入標准錯誤的所有內容都將與標准輸出一起放入同一文件。 它是使用dup2()輕松實現的。 但是,程序中的標准錯誤流將具有其自己的緩沖區,而程序中的標准輸出流將具有其自己的緩沖區,因此,如果將輸出轉到文件,則輸出的交織不會完全確定。

您以兩種不同的方式運行命令,並且(毫不奇怪)獲得了兩種不同的結果。

  1. ./a.out > outfile 2>&1

    I / O重定向從左到右處理。 第一個將標准輸出發送到outfile 第二發送標准誤差同一個地方標准輸出,所以它去outfile了。

  2. ./a.out 2>&1 >outfile

    第一次重定向會將標准錯誤發送到要輸出標准輸出的位置,即當前的終端。 然后,第二次重定向將標准輸出發送到文件(但是將標准錯誤發送到終端)。

該程序使用printf()函數和write()系統調用。 使用printf()函數時,它將緩沖其輸出。 如果輸出要發送到終端,則通常是“行緩沖”的,因此當將換行符添加到緩沖區時,將顯示輸出。 但是,當輸出將要發送到文件時,它將被“完全緩沖”,並且只有在刷新或關閉文件流或填充緩沖區后,輸出才會出現。 請注意, stderr尚未完全緩沖,因此寫入其中的輸出會立即顯示。

如果在不進行任何I / O重定向的情況下運行程序,則會看到:

standard output. 
standard err, output

相比之下, write()系統調用立即將數據傳輸到輸出文件描述符。 在該示例中,您寫入標准錯誤,並且寫入的內容將立即顯示。 如果您使用了fprintf(stderr, ...)也會發生同樣的情況。 但是,假設您修改了程序以寫入STDOUT_FILENO; 然后,當輸出到文件時,輸出將按以下順序顯示:

standard err, output
standard output. 

因為在緩沖printf()同時write()是未緩沖的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM