我試圖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
再說一遍,但現在循環printf
中while
不支持\n
.
printf "%s\0" $'x\n' y z | while IFS='' read -r -d $'\0' line
do
printf "%s" "$line"
done
輸出:
x
yz(...)
我添加了(...)
,這意味著第二行末尾沒有行尾。但文字仍然會被處理和列印。