该脚本输出 5 行,第三行加下划线:
#!/usr/bin/env bash
set -eu
bold=$(tput bold)
reset=$(tput sgr0)
underline=$(tput smul)
echo 'line 1
line 2
line 3
line 4
line 5' | awk -v bold="$bold" -v reset="$reset" -v underline="$underline" '
NR == 3 {print underline $0 reset}
NR != 3 {print $0}
'
如果我没有在第三行的末尾重置(在脚本中),那么以下所有行都带有下划线,包括我接下来键入的命令(在 shell 中)。直到我跑reset
。使用less
( ./my-script.sh | less -R
) 不仅reset
(在脚本中)不需要(第三行加下划线),而且它还在tmux
( ^O
, TERM=screen-256color
) 中产生额外的符号:
line 1
line 2
line 3^O
line 4
line 5
但在普通控制台 ( TERM=xterm-256color
) 中没有符号。
究竟是什么以及为什么会发生这种情况?有没有办法让脚本在所有这些情况下都能正常工作?
$ ./my-script.sh
$ ./my-script.sh | grep line --color=never
$ ./my-script.sh | less -R
例如,使以下脚本更好地工作。
less
在行尾发送它自己的“重置”,这恰好是sgr0
通过(ncurses)消除^O
(重置备用字符集)从terminfo派生的,因为less
使用的是termcap接口。如手册页curs_termcap(3x)中所述,对应于 terminfo sgr0的 termcap 功能me通常不会修改备用字符集状态:也许
less
正在执行该重置以从意外的转义序列中恢复:该-R
选项仅设计用于处理 ANSI 颜色(以及类似格式的转义,例如粗体、下划线、闪烁、突出)。源代码没有提到这一点,但A_NORMAL
分配告诉less
稍后发出重置:作为替代方案
sgr0
(它会重置所有视频属性,并且只被更少的部分理解),您可以这样做和(对于许多终端/许多系统,包括
TERM=screen-256color
)仅重置下划线。但是,这不会影响粗体,也没有传统的 terminfo/termcap 功能来重置粗体。但是 screen 实现了执行此操作的相应 ECMA-48 序列(SGR 22 与 中使用的 24rmul
),因此您可以对这种情况进行硬编码。