2017-04-15 22 views
1

リダイレクトを使用した色付けとスタイリングを可能にするさまざまなスタイルオプションを使用して、bash用のカラー出力ライブラリを作成しようとしています。パイプでのBashテストで奇妙な動作が発生する

echo "Red" | red出力赤のテキスト

echo "Bold" | bold出力太字

echo "Yellow bold" | yellow | bold出力太字黄色のテキスト

次のように私がこれまで書いたコードは次のとおりです。

#shellcheck shell=bash 

# set debug 
# set -o xtrace 

# number of colors supported 
__colors=$(tput colors 2> /dev/null) 
# colors 
__black="$(tput setaf 0)" 
__red="$(tput setaf 1)" 
__green="$(tput setaf 2)" 
__yellow="$(tput setaf 3)" 
__blue="$(tput setaf 4)" 
__magenta="$(tput setaf 5)" 
__cyan="$(tput setaf 6)" 
__white="$(tput setaf 7)" 
# style 
__default="$(tput sgr0)" 
__bold="$(tput bold)" 
__underline="$(tput smul)" 


function has_colors() { 
    COLOR=${COLOR:-auto} 
    if [[ $COLOR = 'never' ]]; then 
    return 1 
    elif [[ $COLOR = 'always' ]]; then 
    return 0 
    else 
    # check if stoud is terminal and terminal supports colors 
    [[ -t 1 ]] && \ 
    [[ -n $__colors ]] && \ 
    [[ $__colors -ge 8 ]] 
    fi 
} 

function __style() { 
    read -r input 
    if has_colors; then 
    echo -e "$1" "$input" "$__default" 
    else 
    echo -e "$input" 
    fi 
} 

function black() { 
    __style "$__black" 
} 

function red() { 
    __style "$__red" 
} 

function green() { 
    __style "$__green" 
} 

function yellow() { 
    __style "$__yellow" 
} 

function blue() { 
    __style "$__blue" 
} 

function magenta() { 
    __style "$__magenta" 
} 

function cyan() { 
    __style "$__cyan" 
} 

function white() { 
    __style "$__white" 
} 

function bold() { 
    __style "$__bold" 
} 

function underline() { 
    __style "$__underline" 
} 

は、色を設定=常にエスケープコードとすべての時間を出力します。一方、COLOR = autoは、現在のstdoutが端末であり、端末が色をサポートしていることを確認するためにいくつかのチェックを実行します。

問題

は常に最後のスタイリングオプションを適用しworking.Itとは思われない複数のスタイリングオプションを使用しています。たとえば:

echo "Yellow bold" | yellow | boldは、太字のテキストを出力しますが、黄色ではありません。一方

echo "Bold yellow" | bold | yellow出力黄色のテキストが、太字ではありません。

面白いのは、 COLOR =を常にうまく使っているようです。それで、stdoutが端末[[ -t 1 ]]であるかどうかを調べるためのテストのように見えます。そのテストで何らかの遅れがあるので、私はそれがわからない。しかし、私が[[ -t 1 ]]ビットを削除すると、動作します。

どのように私はこれを達成することができますか? Bashの専門家ではなく、シェルがどのように機能するのかここでかなり混乱しています。

+1

問題が '黄色にすることです|黄色のstdoutはttyではありません。各色の機能をチェックする代わりに、メインスクリプトを一度チェックして、すべての機能が他の人の –

+0

@を使用するという変数を設定する必要があります。一度チェックして出力をファイルにリダイレクトすると、カラーエスケープコードで表示されます。私は欲しいのではない – Bren

+0

set -xvの出力を見ると、太字(2番目と仮定)がスタイル内でecho -e行の前に呼び出され、元の文字列のコピーを受け取っているしたがって、あなたは同じように多くの変更を行うことができ、その結果は常に標準テキストで太字になります。どういうわけか、各パイプに順番にデータを受信させる必要があります(最良の方法ではわからない)。あなたはwaitコマンドを調べることができますか? – grail

答えて

0

これを明確な頭で見ると、私のアプローチでは問題が見つかりました。

[[ -t 1 ]]テスト出力を示す機能yellowを通過すると、端末でないとき、私echo "Hello" | yellow | boldのようなパイプ2つの機能、[[ -t 1 ]]がfalseの場合stdoutは、ターミナルである場合。関数(黄色)の出力は、第二の機能(太字)にパイプされているためである

。そのため、黄色のエスケープコードを出力せず、入力だけを出力します。私はecho "Hello" | yellow | bold | underlineのように別の関数に配管を保持する場合

だから、出力のみを強調します。

これは色で出力素晴らしく、簡単な方法であると思われたが、今私は、現在実行中の関数はパイプが、リダイレクトされないされているかどうかを知る方法がない限り、私のアプローチを変更することがありますか?

EDIT

This postコマンドがリダイレクトされるか、またはパイプされるかどうかを検出する方法があることを示します。

このアプローチでは、パイプラインで色を無効にしないと、別の出力スタイリング機能ではない別のコマンドにパイプされたときにカラーコードが出力されるため、

は、アプローチを変更:それ多分エッジケースが、それでも溶液を100障害証拠

EDITソリューション%ではありません。代わり配管形式で次々には以下のように最初のパラメータとして、次の形式のオプションを使用すると、最終的なコードであるトリック

echo "Hello" | yellow bold underline

は以下ん

#shellcheck shell=bash 

# set debug 
# set -xv 

# number of colors supported 
__colors=$(tput colors 2> /dev/null) 

# foreground colors 
__black="$(tput setaf 0)" 
__red="$(tput setaf 1)" 
__green="$(tput setaf 2)" 
__yellow="$(tput setaf 3)" 
__blue="$(tput setaf 4)" 
__magenta="$(tput setaf 5)" 
__cyan="$(tput setaf 6)" 
__white="$(tput setaf 7)" 

# background colors 
__bg_black="$(tput setab 0)" 
__bg_red="$(tput setab 1)" 
__bg_green="$(tput setab 2)" 
__bg_yellow="$(tput setab 3)" 
__bg_blue="$(tput setab 4)" 
__bg_magenta="$(tput setab 5)" 
__bg_cyan="$(tput setab 6)" 
__bg_white="$(tput setab 7)" 

# style 
__reset="$(tput sgr0)" 
__bold="$(tput bold)" 
__underline="$(tput smul)" 

function has_colors() { 
    COLOR=${COLOR:-auto} 
    if [[ $COLOR = 'never' ]]; then 
    return 1 
    elif [[ $COLOR = 'always' ]]; then 
    return 0 
    else 
    [[ -t 1 ]] && [[ -n $__colors ]] && [[ $__colors -ge 8 ]] 
    fi 
} 

function __format() { 
    local format="$1" 
    local next="${2:-}" # next formatting function e.g. underline 
    if has_colors; then 
    echo -en "$format" 
    if [[ -n $next ]]; then 
     shift 2 
     tee | "$next" "[email protected]" 
    else 
     tee 
     echo -en "$__reset" 
    fi 
    else 
    tee #print output 
    fi 
} 

function black() { __format "$__black" "[email protected]"; } 
function red() { __format "$__red" "[email protected]"; } 
function green() { __format "$__green" "[email protected]";} 
function yellow() { __format "$__yellow" "[email protected]"; } 
function blue() { __format "$__blue" "[email protected]"; } 
function magenta() { __format "$__magenta" "[email protected]";} 
function cyan() { __format "$__cyan" "[email protected]";} 
function white() { __format "$__white" "[email protected]";} 

function bg_black() { __format "$__bg_black" "[email protected]"; } 
function bg_red() { __format "$__bg_red" "[email protected]"; } 
function bg_green() { __format "$__bg_green" "[email protected]";} 
function bg_yellow() { __format "$__bg_yellow" "[email protected]"; } 
function bg_blue() { __format "$__bg_blue" "[email protected]"; } 
function bg_magenta() { __format "$__bg_magenta" "[email protected]";} 
function bg_cyan() { __format "$__bg_cyan" "[email protected]";} 
function bg_white() { __format "$__bg_white" "[email protected]";} 

function bold() { __format "$__bold" "[email protected]";} 
function underline() { __format "$__underline" "[email protected]"; } 
+1

パイプラインがパイプに送られているのか、リダイレクトされているのかを判断する最良の方法は、コマンドを検査することです。 stdoutがtty( 'test -t')であれば起動時にメインシェルをチェックインし、グローバル変数を設定します。各関数で、その変数を調べます。スクリプト内で、パイプラインをファイルにリダイレクトしても、色付け関数は呼び出されません!個人的意見:これを気にしないでください。色の見た目はすばらしく見えますが、シェルはこの種のものでは壊れやすく、最終的には午前3時にログファイルを見て、十分なコーヒーがなく、クラフトでうんざりしていないことを望みます。 –

+0

@WilliamPursell私は再利用可能なライブラリになるように書いています。将来はいつかファイルにリダイレクトされると思います。私はこれを壊すと、それは私のために非常に非常に役立つことになると思う。それは今のところ個人的な使用のためだけです。それが有用であることが証明され、私が思うよりも適切なテストをすれば、多くの面倒を節約できます。か否か ?私は私の答えを更新し、私はこれに良い簡単な解決策を見つけたと思う。私はsshが別の話であることを知っている、それがsshやソケットを通してどのように動作するか見るための遊びを持つだろう。何かご意見は ? – Bren

+1

あなたのソリューションはいいです(しかし余分なioを生成し、複数の行出力に失敗します;おそらく単に 'red; underline;テキストをエコーし​​ます; default'))、必然的にこの種のものはそれ以上の騒音になります。コード内のシンプルさが最終的にカラー化された出力の利点を上回ります。そして、「結局のところ」は予想以上に早く起こります! –

関連する問題