Redireciona a saída para stdout ou um arquivo (não ambos)

1

Eu quero criar um script que, quando chamado interativamente, grava em stdout, mas se chamado de outro script e a variável EVENT_LOGGER é definida pelo script de chamada, grava no arquivo EVENT_LOGGER.

Provavelmente, existe uma maneira fácil de fazer isso, mas isso não está vindo para mim. Eu certamente posso adicionar essa lógica a todo lugar onde a saída é gerada:

if [[ -f $EVENT_LOGGER ]]
then
   echo "Some message" >> $EVENT_LOGGER
else
   echo "Some message"
fi

mas isso adicionará muito volume ao script.

Espero poder fazer algo assim:

if [[ ! -f $EVENT_LOGGER ]]
then
   EVENT_LOGGER = "&1"
fi

Então, todos os comandos de saída seriam:

echo "Some message" >> $EVENT_LOGGER

e eles iriam para o arquivo ou stdout, seja qual for o EVENT_LOGGER.

Isso não funcionou. Existe outra maneira de ter $ EVENT_LOGGER resolvido para stdout?

Estou usando o ksh93 no AIX 7.1

    
por Scavenger 05.01.2018 / 21:40

2 respostas

4

Em muitas variantes do Unix, você pode acessar a saída padrão através do nome do arquivo /dev/stdout , assim:

if [[ -z $EVENT_LOGGER ]]; then
  EVENT_LOGGER=/dev/stdout
fi
…
echo >>"$EVENT_LOGGER" 'This is a log message'

No entanto, não tenho certeza se está disponível no AIX. Consulte Portabilidade de "> / dev / stdout" e Sistemas Unix sem / dev / stdin, / dev / stdout e / dev / stderr?

Como alternativa, mantenha todos os registros em stdout e, opcionalmente, redirecione o stdout para um arquivo. Se você chamar o exec construído sem nome de comando, mas com redirecionamentos, isso definirá os redirecionamentos para o restante do script.

if [[ -n $EVENT_LOGGER ]]; then
  exec >>"$EVENT_LOGGER"
fi
…
echo 'This is a log message'

Observe que a saída de programas chamados pelo script irá para o mesmo arquivo de log. Se você não quiser isso, faça o registro em outro descritor de arquivo.

if [[ -n $EVENT_LOGGER ]]; then
  exec 3>>"$EVENT_LOGGER"
else
  exec 3>&1
fi
…
echo >&3 'This is a log message'

Ainda outra abordagem é definir uma função de maneiras diferentes dependendo do que é desejado.

if [[ -n $EVENT_LOGGER ]]; then
  log () {
    echo "$*" >>"$EVENT_LOGGER"
  }
else
  log () {
    echo "$*"
  }
fi
…
log 'This is a log message'

Não importa o que você faça, recomendo usar uma função. Dessa forma, se você quiser alterar a forma como o log funciona (por exemplo, para o terminal e para um arquivo, adicionar cores, torná-lo condicional, ...), será muito mais fácil.

Algumas notas gerais:

  • O teste -f testa se existe um arquivo. Este não é um bom teste aqui. Em vez disso, teste se a variável não estiver vazia, com -n ( -z testa se está vazia).
  • Você não pode colocar espaços ao redor do sinal = em uma atribuição de variável.
por 05.01.2018 / 21:56
1

Você quer isso:

$ cat interactive.sh
#!/bin/bash
if [[ -n "$EVENT_LOGGER" ]]; then
    exec 1>>"$EVENT_LOGGER"
fi
date
echo "hello world"

O molho mágico: exec 1>>"$EVENT_LOGGER" redireciona o stdout para a duração do script.

Demo:

  1. variável não definida, saída para stdout

    $ bash interactive.sh
    Sat Jan  6 19:06:02 EST 2018
    hello world
    
  2. variável definida, saída para arquivo

    $ env EVENT_LOGGER="./event.logger" bash interactive.sh
    $ cat event.logger
    Sat Jan  6 19:06:13 EST 2018
    hello world
    
por 07.01.2018 / 01:09