2017-04-15 1 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 = 항상 항상 이스케이프 코드를 사용하여 출력합니다. 반면에 COLOR = auto는 현재 stdout이 터미널이고 터미널이 색상을 지원하는지 확인하기 위해 일부 검사를 수행합니다.

문제는 여러 스타일 옵션을 사용하면 작동하지 않는 것 같습니다. 마지막 스타일 옵션이 항상 적용됩니다. 예를 들면 다음과 같습니다.

echo "Yellow bold" | yellow | bold은 굵은 텍스트를 출력하지만 노란색은 표시하지 않습니다. 한편

:

echo "Bold yellow" | bold | yellow 출력 노란색 텍스트하지만 굵게.

웃기는 건; COLOR 설정 = 항상 잘 작동하는 것 같습니다. 그래서 stdout이 terminal [[ -t 1 ]]인지 확인하기 위해 수행하는 테스트와 같습니다. 나는 그 시험에 어떤 종류의 지체가 있기 때문에 그것이 맞는지 확신 할 수 없다. 하지만 [[ -t 1 ]] 비트를 제거하면 작동합니다.

어떻게하면 될까요? Bash 나 쉘이 어떻게 작동하는지에 대해서는 전문가가 아닙니다. 꽤 혼란스러워.

+1

문제는 대신 배관 형식의 다음과 같은 첫 번째 매개 변수로 사용하여 다른 다음 형식 옵션 하나씩는 마지막 코드는

echo "Hello" | yellow bold underline

은 다음 트릭을 수행 굵은 글씨 ','황색 '의 표준 출력은 tty가 아닙니다. 각 색상 기능을 검사하는 대신 주 스크립트를 한 번 확인하고 모든 기능에서 다른 사람 ( –

+0

@)을 사용하는 변수를 설정해야합니다. 그 이유는 바로 그 이유입니다. 한 번 확인하고 출력을 파일로 리디렉션하면 색상 이스케이프 코드가 표시됩니다. 어느 쪽이 좋을지 모르겠다 – Bren

+0

set -xv 출력을 보면, 굵은 글씨 (두 번째라고 가정)가 스타일 내에서 echo -e 줄보다 먼저 호출되고 원래 문자열의 사본을 받는다는 사실에서 나온 것처럼 보입니다 따라서 당신은 inbetween와 같은 많은 변화를 할 수 있으며 결과는 항상 표준 텍스트로 볼드체가됩니다. 어떻게 든 각 파이프가 차례대로 데이터를 수신하도록해야합니다 (가장 좋은 방법은 확실하지 않음). wait 명령을 살펴볼 수 있습니까 ?? – grail

답변

0

명확한 머리를 가진 이걸 보면서, 나는 나의 접근법에서 문제를 발견했다.

[[ -t 1 ]]yellow 테스트 기능을 통해 갈 때 I 파이프 두 함수 echo "Hello" | yellow | bold 같은 [[ -t 1 ]] 출력을 나타내는 것은 아니다 단말 false이면 stdout이 단말 인 경우.

기능 (노란색)의 출력이 두 번째 기능 (굵게)으로 파이프되기 때문입니다. 그래서 노란색에 대한 이스케이프 코드를 출력하지 않고 입력을 출력합니다.

그래서 파이핑을 echo "Hello" | yellow | bold | underline과 같은 다른 함수로 계속 사용하면 출력에만 밑줄을 긋습니다.

이것은 색상으로 출력하는 멋지고 쉬운 방법 인 것처럼 보였습니다. 그러나 현재 실행중인 함수가 파이프로 연결되어 있지만 리디렉션되지 않았는지 알 수있는 방법이 없으면 이제는 접근 방식을 변경해야합니다.

편집

This post 명령은 리디렉션 또는 파이프되는 경우 감지하는 방법이 표시됩니다.

아직까지는이 방법이 유용하지 않습니다. 왜냐하면 파이프되었을 때 색상을 비활성화하지 않으면 다른 출력 스타일 지정 기능이 아닌 다른 명령으로 파이프 될 때 색상 코드가 출력되기 때문입니다.

이 접근 방식을 변경 : 그건 아마 가장자리 경우, 여전히 해결책은 100 오류 증거

편집 솔루션 % 이하이다. | 그 노란색`에서

#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'). 필연적으로 이런 종류의 것은 가치가있는 것보다 더 많은 소음이됩니다. 코드의 단순성은 결국 컬러화 된 출력의 이점보다 중요합니다. 그리고 "결국"예상보다 놀랍게 빨리 일어납니다! –

관련 문제