web-dev-qa-db-ja.com

少ないテキスト属性をリセットする必要がないのはなぜですか?

このスクリプトは5行を出力し、3行目に下線が引かれています。

#!/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}
'

3行目の終わりで(スクリプトで)リセットしないと、次に(シェルで)入力するコマンドを含め、次のすべての行に下線が引かれます。 resetを実行するまで。 less./my-script.sh | less -Rreset(スクリプト内)は不要である(3行目に下線が引かれている)だけでなく、tmux^OTERM=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

たとえば、 次のスクリプト をより適切に機能させるため。

3
x-yuri

lessは、行の終わりに独自の「リセット」を送信します。これは、terminfo sgr0から(ncurses)によって^O(代替文字セットをリセット)を削除することによって派生します。 lessはtermcapインターフェースを使用しています。 terminfosgr0に対応するtermcap機能meは、マニュアルページに記載されているように、通常、代替文字セットの状態を変更しません。 curs_termcap(3x)

Termcapには、terminfoのsgr文字列に類似したものは何もないことに注意してください。この結果の1つは、termcapアプリケーションがme(terminfosgr0)代替文字セットはリセットされません。この実装は、この点で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の代わりに(allビデオをリセットします属性、そして一部しか理解されていない)、あなたはすることができます

reset=$(tput rmul)

および(TERM=screen-256colorを含む多くの端末/多くのシステムの場合)下線だけをリセットします。ただし、それはboldには影響せず、太字をリセットする従来のterminfo/termcap機能もありません。 。ただし、screenはこれを行う対応するECMA-48シーケンスを実装しているため(SGR22とrmulで使用される24)、その場合はハードコーディングできます

3
Thomas Dickey