如何根据条件告诉 Bash 中的 echo/printf 吞下转义码?

如何根据条件告诉 Bash 中的 echo/printf 吞下转义码?

我有一个 Bash 脚本,它作为一项作业以交互方式运行cron。当交互运行时,它会在终端上输出彩色文本。然而,当运行时cron它没有终端,因此我[1;31m在输出中得到大量类似的结果。

如果输出设备不支持转义码,Bash 有没有办法告诉它吞掉转义码?

这与如何检查 bash 是否可以打印颜色这是关于检查条件。但是,我希望在调用echoprintf同时保留颜色的双重功能或不取决于输出设备时尽可能少地进行更改。

答案1

检查您是否正在打印到终端。当你告诉GNUls和 GNU等程序时,它们就会这么做。grep--color=auto

即使您正在打印到终端,理论上,它也可能无法理解变色转义序列。实际上,所有常见和最不常见的终端都理解这些序列:我见过的所有 X11 终端仿真器、screen、tmux、Linux 控制台、*BSD 控制台、PuTTY、rxvt、Console2、ConEmu、 ……

normal=
green=
if [ -t 1 ]; then
  normal=$'\e[0m'
  green=$'\e32m'
 fi
 echo "foobar ${green}OK${normal}"

该测试[ -t 1 ]针对标准输出和[ -t 2 ]标准错误。

在不支持$'…'扩展的 shell 中,您可以使用以下命令生成可移植的转义字符esc=$(echo _ | tr _ '\033')

答案2

不完全是吞咽,但你可以通过参数扩展来删除它们:

str='Hello \e[31mc\e[32mo\e[33ml\e[34mo\e[35mr\e[m world'

# colorful output
echo -e "$str"

# colorless output    
echo -e "${str//\\e\[+([0-9;])m}"

上面的内容bash需要extglob打开 shell 选项。 ( shopt -s extglob)

为了方便使用,定义一个函数:

function ecco() { [ -t 1 ] && echo -e "$1" || echo -e "${1//\\e\[+([0-9;])m}"; }

然后你只需调用它:

ecco 'Hello \e[31mc\e[32mo\e[33ml\e[34mo\e[35mr\e[m world'

要检查它是否有效,只需重定向其输出,颜色就会消失:

ecco 'Hello \e[31mc\e[32mo\e[33ml\e[34mo\e[35mr\e[m world' | cat

答案3

您应该在脚本中检查它是否以交互方式运行?

http://www.gnu.org/software/bash/manual/html_node/Is-this-Shell-Interactive_003f.html

引号:

6.3.2 这个 Shell 是交互式的吗?

要确定启动脚本中的 Bash 是否以交互方式运行,请测试“-”特殊参数的值。当 shell 是交互式的时它包含 i。例如:

case "$-" in
  *i*)   echo This shell is interactive ;;
   *)    echo This shell is not interactive ;;
esac

或者,启动脚本可以检查变量 PS1;它在非交互式 shell 中未设置,并在交互式 shell 中设置。因此:

if [ -z "$PS1" ]; then
   echo This shell is not interactive
else
   echo This shell is interactive
fi

如果是交互式的,则定义一组变量为“_escape_codes_”,如果不是,则定义为“”,并使用这些变量对脚本中的输出进行着色(在交互式环境中,它们将具有转义码,在非交互式环境中,它们将添加与正文无关)。

前任:

case "$-" in
  *i*)    _bold_="$(printf '\033[1m')"
          _norm_="$(printf '\033[0m')"
          ;;
  *)      _bold_=""
          _norm_=""
          ;;
esac
echo "this ${_bold_}text${_norm_} is important"

相关内容