Como posso dizer ao echo / printf no Bash para engolir os códigos de escape, com base em uma condição?

2

Eu tenho um script Bash que está sendo executado de forma interativa e como um trabalho cron . Quando executado interativamente, ele exibe texto colorido no terminal. No entanto, quando executado em cron , ele não tem um terminal e, portanto, eu recebo muitos [1;31m e similares na saída.

Existe uma maneira no Bash de dizer para engolir os códigos de escape se o dispositivo de saída não os suporta?

Isso está relacionado a Como verificar se o bash pode imprimir cores que é sobre a verificação da condição. No entanto, quero alterar o mínimo possível na invocação de echo ou printf , mantendo a funcionalidade dupla de cores ou não, dependendo do dispositivo de saída.

    
por 0xC0000022L 19.11.2013 / 20:30

3 respostas

2

Não é exatamente engolido, mas você pode removê-los com a expansão de parâmetros:

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}"

O acima em bash requer que a opção extglob shell esteja ativada. ( shopt -s extglob )

Para facilitar o uso, defina uma função:

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

Então você acabou de ligar:

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

Para verificar se funciona, basta redirecionar sua saída e as cores desaparecerão:

ecco 'Hello \e[31mc\e[32mo\e[33ml\e[34mo\e[35mr\e[m world' | cat
    
por 19.11.2013 / 20:45
3

Verifique se você está imprimindo em um terminal. Isso é o que programas como o GNU ls e o GNU grep fazem quando você diz a eles --color=auto .

Mesmo se você estiver imprimindo em um terminal, em teoria, ele pode não entender as seqüências de escape que mudam de cor. Na prática, todos os terminais comuns e mais não tão comuns entendem essas sequências: todos os emuladores de terminal X11 que eu já vi, tela, tmux, o console do Linux, os consoles * BSD, PuTTY, rxvt, Console2, ConEmu, …

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

O teste é [ -t 1 ] para saída padrão e [ -t 2 ] para erro padrão.

Em shells que não suportam a expansão $'…' , você pode gerar um caractere de escape portável com esc=$(echo _ | tr _ '3')

    
por 20.11.2013 / 01:11
1

você deve apenas verificar, no seu script, se ele está sendo executado de forma interativa ou não?

link

Citações:

6.3.2 Is this Shell Interactive?

To determine within a startup script whether or not Bash is running interactively, test the value of the ‘-’ special parameter. It contains i when the shell is interactive. For example:

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

Alternatively, startup scripts may examine the variable PS1; it is unset in non-interactive shells, and set in interactive shells. Thus:

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

e defina um conjunto de variáveis para "_escape_codes_" se for interativo e para "" se não, e use essas variáveis para colorir a saída no script (no ambiente interativo elas terão códigos de escape, no não interativo eles não adicionarão nada ao texto).

ex:

case "$-" in
  *i*)    _bold_="$(printf '3[1m')"
          _norm_="$(printf '3[0m')"
          ;;
  *)      _bold_=""
          _norm_=""
          ;;
esac
echo "this ${_bold_}text${_norm_} is important"
    
por 19.11.2013 / 20:43