我试图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(...)
我添加了(...)
,这意味着第二行末尾没有行尾。但文本仍然会被处理和打印。