Terminal

為什麼我不需要用less來重置文本屬性?

  • May 29, 2018

該腳本輸出 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通常不會修改備用字元集狀態:

請注意,termcap 與 terminfo 的**sgr字元串沒有任何相似之處。這樣做的一個後果是 termcap 應用程序假定me**(terminfo sgr0) 不會重置備用字元集。此實現檢查並修改顯示到 termcap 介面的數據,以適應 termcap 在這方面的限制。

也許less正在執行該重置以從意外的轉義序列中恢復:該-R選項僅設計用於處理 ANSI 顏色(以及類似格式的轉義,例如粗體、下劃線、閃爍、突出)。原始碼沒有提到這一點,但A_NORMAL分配告訴less稍後發出重置:

   /* 
    * Add a newline if necessary, 
    * and append a '\0' to the end of the line. 
    * We output a newline if we're not at the right edge of the screen, 
    * or if the terminal doesn't auto wrap, 
    * or if this is really the end of the line AND the terminal ignores 
    * a newline at the right edge. 
    * (In the last case we don't want to output a newline if the terminal  
    * doesn't ignore it since that would produce an extra blank line. 
    * But we do want to output a newline if the terminal ignores it in case
    * the next line is blank.  In that case the single newline output for 
    * that blank line would be ignored!) 
    */
   if (column < sc_width || !auto_wrap || (endline && ignaw) || ctldisp == OPT_ON) 
   {
           linebuf[curr] = '\n';
           attr[curr] = AT_NORMAL;
           curr++;
   }

作為替代方案**sgr0(它會重置所有**影片屬性,並且只被更少的部分理解),您可以這樣做

reset=$(tput rmul)

和(對於許多終端/許多系統,包括TERM=screen-256color)僅重置下劃線。但是,這不會影響粗體,也沒有傳統的 terminfo/termcap 功能來重置粗體。但是 screen 實現了執行此操作的相應 ECMA-48 序列(SGR 22 與 中使用的 24 rmul),因此您可以對這種情況進行硬編碼。

引用自:https://unix.stackexchange.com/questions/446532