標準輸出的重定向忽略沒有換行符號的行

標準輸出的重定向忽略沒有換行符號的行

我試圖stderr在終端中將我的列印為紅色。下面的腳本將重定向到偵錯陷阱時的2自訂。8

exec 9>&2
exec 8> >(
    while IFS='' read -r line || [ -n "$line" ]; do
       echo -e "${RED}${line}${COLORRESET}"
    done
)
function undirect(){ exec 2>&9; } # reset to original 9 (==2)
function redirect(){ exec 2>&8; } # set to custom 8
trap "redirect;" DEBUG
PROMPT_COMMAND='undirect;'

它來自這裡,並有明確的解釋。

似乎工作得很好,但是非換行符終止的輸入根本不會被印出來。引用作者的話戈斯佩斯再次:

bash> echo -en "hi\n" 1>&2
    hi       <-- this is red
bash> echo -en "hi" 1>&2
bash> echo -en "hi" 1>&2
bash> echo -en "hi\n" 1>&2
    hihihi   <-- this is red

我不明白為什麼。非換行內容似乎最終出現在某種緩衝區。它要么甚至沒有到達文件描述符8,要么以某種方式不想立即打印出來。它去哪裡?redirect每次都會被正確地呼叫。另外,IFS=''意味著沒有分隔符,所以我不太明白為什麼回顯是按8行發生的。

錯誤修復將不勝感激,我將引用的答案連結到這個問題。

正如吉爾斯所指出的,整個解決方案並不十分完美。我在讀取、標準輸入、進度條方面遇到問題,既不能su也不能source。經常出現諸如管道破裂和意外的航站樓出口等重大問題。如果有人透過我的連結到達這裡,請考慮使用https://github.com/sickill/stderred相反,它要好得多(還沒有問題)(但echo bla >&2仍然是非紅色和相應的問題已關閉

答案1

您確實獲得了部分行輸出,作為列印換行符的同一行的一部分。該行的部分在 內緩衝read這就是它的作用

實用程式應從標準輸入讀取單一邏輯行

例如,<foobar>一秒後列印,而不是<foo><bar>.

(echo -n foo ; sleep 1 ; echo bar) | (read x ; echo "<$x>")

如果您想捕獲比整行更小的輸入,則需要執行其他操作,例如使用 Perl。這將列印<foo><bar\n>(在最後一個之前有換行符>,因為與 不同read,Perl 不會專門處理最後的換行符。與著色無關。)

(echo -n foo ; sleep 1 ; echo bar) | 
    perl -e '$|=1; while(sysread STDIN,$a,9999) { print "<$a>"}'

如果您在環境中匯出了顏色 (RED和)的控製程式碼,則可以從 Perl 腳本中使用它們,如下所示:COLORRESET

perl -e '$|=1; while(sysread STDIN,$a,9999) {print "$ENV{RED}$a$ENV{COLORRESET}"}'

答案2

在 Bash 中,您可以使用-d內建選項read,它定義行尾符號。man bash指出:

-d delim    The first character of delim is used to terminate the input line, 
            rather than newline.

如果未定義,read則等待\n出現將字串視為一行。但是當您使用該-d選項時,您可以將其設定NUL為分隔符號。當然,您還需要以 NUL 終止輸入。

例子:

printf "%s\0" $'x\n' y z | while IFS='' read -r -d $'\0' line
    do
        printf "%s\n" "$line"
    done

輸出:

x

y
z

再說一遍,但現在循環printfwhile不支持\n.

printf "%s\0" $'x\n' y z | while IFS='' read -r -d $'\0' line
    do
        printf "%s" "$line"
    done

輸出:

x
yz(...)

我添加了(...),這意味著第二行末尾沒有行尾。但文字仍然會被處理和列印。

相關內容