Linux 管道中的Bash测试会导致奇怪的行为
我正在尝试为bash编写一个彩色输出库,其中包含各种样式选项,允许使用重定向进行着色和样式设置 e、 gLinux 管道中的Bash测试会导致奇怪的行为,linux,bash,shell,pipe,echo,Linux,Bash,Shell,Pipe,Echo,我正在尝试为bash编写一个彩色输出库,其中包含各种样式选项,允许使用重定向进行着色和样式设置 e、 g echo“Red”| Red输出红色文本 及 echo“Bold”| Bold输出粗体文本 及 回显“黄色粗体”|黄色粗体输出粗体黄色文本 到目前为止,我编写的代码如下: #shellcheck shell=bash # set debug # set -o xtrace # number of colors supported __colors=$(tput colors 2>
echo“Red”| Red
输出红色文本
及
echo“Bold”| 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"
}
#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" "$@"
else
tee
echo -en "$__reset"
fi
else
tee #print output
fi
}
function black() { __format "$__black" "$@"; }
function red() { __format "$__red" "$@"; }
function green() { __format "$__green" "$@";}
function yellow() { __format "$__yellow" "$@"; }
function blue() { __format "$__blue" "$@"; }
function magenta() { __format "$__magenta" "$@";}
function cyan() { __format "$__cyan" "$@";}
function white() { __format "$__white" "$@";}
function bg_black() { __format "$__bg_black" "$@"; }
function bg_red() { __format "$__bg_red" "$@"; }
function bg_green() { __format "$__bg_green" "$@";}
function bg_yellow() { __format "$__bg_yellow" "$@"; }
function bg_blue() { __format "$__bg_blue" "$@"; }
function bg_magenta() { __format "$__bg_magenta" "$@";}
function bg_cyan() { __format "$__bg_cyan" "$@";}
function bg_white() { __format "$__bg_white" "$@";}
function bold() { __format "$__bold" "$@";}
function underline() { __format "$__underline" "$@"; }
设置颜色=始终输出转义码。另一方面,COLOR=auto执行一些检查,以确保当前stdout是终端并且终端支持颜色
问题是使用多个样式选项似乎不起作用。它始终应用最后一个样式选项。例如:
echo“Yellow bold”| Yellow | bold
输出粗体文本,但不输出黄色
另一方面:
echo“Bold yellow”| Bold | yellow
输出黄色文本,但不输出粗体文本
有趣的是;设置COLOR=似乎总是很好地工作。因此,我执行的测试似乎是为了确定stdout是否是终端[[-t1]]
导致了这种情况。我不确定这是否是因为该测试有某种延迟。但是当我删除[[-t1]]
位时,它就工作了
你知道我怎样才能做到这一点吗?不是Bash专家,也不知道shell是如何工作的。这里相当混乱。头脑清醒地看待这一点,我发现我的方法存在问题
[[-t1]]
测试stdout
是否为终端,当我输入两个函数,如回显“Hello”| yellow | bold
,[-t1]]
时,通过函数黄色
表示输出不是终端时,为false
这是因为函数(黄色)的输出通过管道传输到第二个函数(粗体)。这就是为什么它不输出黄色的转义码,只输出输入
因此,如果我继续使用管道连接到另一个函数,如echo“Hello”| yellow | bold | underline
,它只会在输出中加下划线
这似乎是一种用颜色输出的好方法,但现在我必须改变我的方法,除非有办法知道当前运行的函数是否正在被管道传输而不是重定向
编辑
显示了一种检测命令是否被重定向或管道传输的方法
但最终,这种方法似乎不太可行,因为如果我在管道中不禁用颜色,它将在管道连接到另一个命令时输出颜色代码,而该命令不是另一个输出样式功能;这可能是一种边缘情况,但解决方案仍然不是100%无故障的
编辑解决方案:
改变了方法。使用“下一个格式”选项作为第一个的参数,而不是一个接一个地使用管道格式,如下所示
echo“Hello”|黄色粗体下划线
最终代码如下:
#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"
}
#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" "$@"
else
tee
echo -en "$__reset"
fi
else
tee #print output
fi
}
function black() { __format "$__black" "$@"; }
function red() { __format "$__red" "$@"; }
function green() { __format "$__green" "$@";}
function yellow() { __format "$__yellow" "$@"; }
function blue() { __format "$__blue" "$@"; }
function magenta() { __format "$__magenta" "$@";}
function cyan() { __format "$__cyan" "$@";}
function white() { __format "$__white" "$@";}
function bg_black() { __format "$__bg_black" "$@"; }
function bg_red() { __format "$__bg_red" "$@"; }
function bg_green() { __format "$__bg_green" "$@";}
function bg_yellow() { __format "$__bg_yellow" "$@"; }
function bg_blue() { __format "$__bg_blue" "$@"; }
function bg_magenta() { __format "$__bg_magenta" "$@";}
function bg_cyan() { __format "$__bg_cyan" "$@";}
function bg_white() { __format "$__bg_white" "$@";}
function bold() { __format "$__bold" "$@";}
function underline() { __format "$__underline" "$@"; }
以清醒的头脑看待这一点,我发现我的方法存在问题
[[-t1]]
测试stdout
是否为终端,当我输入两个函数,如回显“Hello”| yellow | bold
,[-t1]]
时,通过函数黄色
表示输出不是终端时,为false
这是因为函数(黄色)的输出通过管道传输到第二个函数(粗体)。这就是为什么它不输出黄色的转义码,只输出输入
因此,如果我继续使用管道连接到另一个函数,如echo“Hello”| yellow | bold | underline
,它只会在输出中加下划线
这似乎是一种用颜色输出的好方法,但现在我必须改变我的方法,除非有办法知道当前运行的函数是否正在被管道传输而不是重定向
编辑
显示了一种检测命令是否被重定向或管道传输的方法
但最终,这种方法似乎不太可行,因为如果我在管道中不禁用颜色,它将在管道连接到另一个命令时输出颜色代码,而该命令不是另一个输出样式功能;这可能是一种边缘情况,但解决方案仍然不是100%无故障的
编辑解决方案:
改变了方法。使用“下一个格式”选项作为第一个的参数,而不是一个接一个地使用管道格式,如下所示
echo“Hello”|黄色粗体下划线
最终代码如下:
#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"
}
#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" "$@"
else
tee
echo -en "$__reset"
fi
else
tee #print output
fi
}
function black() { __format "$__black" "$@"; }
function red() { __format "$__red" "$@"; }
function green() { __format "$__green" "$@";}
function yellow() { __format "$__yellow" "$@"; }
function blue() { __format "$__blue" "$@"; }
function magenta() { __format "$__magenta" "$@";}
function cyan() { __format "$__cyan" "$@";}
function white() { __format "$__white" "$@";}
function bg_black() { __format "$__bg_black" "$@"; }
function bg_red() { __format "$__bg_red" "$@"; }
function bg_green() { __format "$__bg_green" "$@";}
function bg_yellow() { __format "$__bg_yellow" "$@"; }
function bg_blue() { __format "$__bg_blue" "$@"; }
function bg_magenta() { __format "$__bg_magenta" "$@";}
function bg_cyan() { __format "$__bg_cyan" "$@";}
function bg_white() { __format "$__bg_white" "$@";}
function bold() { __format "$__bold" "$@";}
function underline() { __format "$__underline" "$@"; }
问题是在黄色|粗体
中,黄色
的标准符号不是tty。您不应该签入每个颜色函数,而应该在主脚本中签入一次,并设置一个变量,使所有函数use@that另一个人,这正是我检查它的原因。如果我检查一次并将输出重定向到一个文件,它将带有颜色转义码。我不想看到set-xv输出,您的问题似乎来自这样一个事实:粗体(假设它是第二个)在样式内的echo-e行之前被调用,并接收原始字符串的副本,因此您可以在两者之间进行任意多的更改,结果将始终是标准文本粗体。不知何故,您需要让每个管道依次接收数据(不确定最佳方法)。您可以查看wait命令??当您确实需要某种三向区分(终端与文件与管道)时,您正在进行双向区分(终端与非终端)。问题是在黄色|粗体
中,黄色
的标准输出不是tty。您不应该签入每个颜色函数,而应该在主脚本中签入一次,并设置一个变量,使所有函数use@that另一个人,这正是我检查它的原因。如果我检查一次并将输出重定向到一个文件,它将带有颜色转义码。我不想看到set-xv输出,您的问题似乎来自这样一个事实,即在使用