击试验,怪异的行为

问题描述:

我尝试写各种造型选项,允许着色和使用重定向造型庆典的彩色输出库。击试验,怪异的行为

例如

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是终端并且终端支持颜色。

这个问题可以用多种造型方案似乎并不被working.It总是适用的最后一个造型的选择。例如:

echo "Yellow bold" | yellow | bold输出大胆的文字,而不是黄色的。

在另一方面:

echo "Bold yellow" | bold | yellow输出黄色文字,而不是大胆。

有趣的是,设置COLOR =总是好像工作得很好。所以它看起来像我执行的测试,看看标准输出是否是终端[[ -t 1 ]]正在造成这种情况。我不确定是否因为测试有某种延迟。但是当我删除[[ -t 1 ]]位时,它可以工作。

任何想法,我怎么能做到这一点?不是Bash的专家,或者shell如何处理这个问题。很困惑在这里。

+1

的问题是,在'黄色|粗体','黄色'的标准输出不是tty。而不是检查每个颜色函数,你应该在主脚本中检查一次,并设置一个变量,所有函数使用 –

+0

@这个人,这正是我检查它的原因。如果我检查一次并将输出重定向到一个文件,它将与颜色转义码一起使用。我不想要 – Bren

+0

看着set -xv输出,你的问题似乎来自这样一个事实,即粗体(假设它是第二个)在样式中的echo -e行之前被调用并接收到原始字符串的副本,因此,您可以在中间进行尽可能多的更改,并且结果始终为标准文本粗体。不知何故,你需要让每个管道依次接收数据(不确定最佳方法)。你可以看看等待命令? – grail

望着这与清醒的头脑,我发现我的方法的问题。

[[ -t 1 ]]测试如果stdout是终端中,当我管2之类的函数echo "Hello" | yellow | bold[[ -t 1 ]]通过功能yellow去时是假,表示输出不是终端。

这是因为函数(黄色)的输出传送到第二函数(粗体)。这就是为什么它不输出黄色的转义码,只是输出输入。

所以,如果我一直管到另一个函数一样echo "Hello" | yellow | bold | underline只会强调输出。

这似乎与色彩输出的一个很好的和简单的方法,但现在我不得不改变我的做法,除非有办法知道当前正在运行的功能正在被管道而不是重定向?

EDIT

This post示出有一种方法,如果命令被重定向或被管道输送到检测。

不过到底这种做法似乎并不十分可行的,因为如果我当管道输送到另一个命令是不是另一个输出造型功能的管道将输出的颜色代码时,不要禁用颜色;这也许边缘的情况下,但仍解决方案不是100%防故障

编辑解决方案:

改变了做法。取而代之的管道格式此起彼伏使用next格式选项作为参数传递给第一个象下面这样的伎俩

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')并设置全局变量,请在启动时检查主shell。在每个函数中,检查该变量。在脚本中,如果将管道重定向到文件,请不要调用彩色化函数!个人意见:不要打扰任何这一点。彩色效果看起来不错,但是这种外壳太脆弱了,最终你会在凌晨3点看到一个没有足够咖啡的日志文件,并希望它不会杂乱无章! –

+0

@WilliamPursell我写作是一个可重用的库,我想我会在未来某个时候将东西重定向到一个文件。我想如果我一旦破解它,这对我来说会非常有帮助。现在真的只是为了个人使用。如果它证明是有用的,并且通过适当的测试,我认为它会省下很多麻烦。或不 ?我更新了我的答案,我想我找到了一个很好的简单解决方案。我知道ssh是不同的故事,将会有一个剧本来看看它是如何通过SSH或套接字工作的。有什么想法吗 ? – Bren

+1

你的解决方案很好(但它确实产生了额外的io,并且失败了多行输出;可能更干净,只做'红色;下划线;回显一些文本;默认值'),但不可避免的是这种事情变得比它的价值更大。代码的简单性最终超过了彩色输出的好处。最终“出乎意料地比预期的更早发生! –