Um script em execução pode identificar o contexto de registro?

2

Digamos que eu redirecione o STDOUT , STDERR de um programa para arquivos.

./script.sh 1> output.log 2> error.log

O programa em execução pode descobrir isso, ou seja, conhecer os caminhos para esses arquivos?

    
por Amarnath Ravikumar 07.04.2014 / 10:16

4 respostas

2

Você pode chamar lsof para listar os arquivos abertos do processo do shell. Use -a -p $$ para limitar a saída ao processo do shell ( $$ ), -d 1 para limitar a saída ao descritor de arquivo 1 (por exemplo) e -F n para imprimir a saída no formato analisável. Aqui está um snippet de shell que lida com caracteres arbitrários em nomes de arquivos:

output_file=$(lsof -a -p $$ -d 1 -F pn; echo .)
output_file=${output_file%.}
output_file=${output_file#n}

Se o nome do arquivo não contiver uma nova linha, você poderá sair com output_file=$(lsof -a -p $$ -d 1 -F pn | sed -n '2s/.//p') .

Observe que o nome do arquivo pode nem sempre existir, especialmente se o arquivo foi excluído.

No Linux, outra maneira de acessar os nomes dos arquivos é através de /proc/$$/fd : /proc/$$/fd/1 é um link simbólico ligeiramente mágico para o arquivo aberto pelo shell no descritor de arquivo 1 (o link funciona mesmo se o nome do arquivo retornado por readlink não existe, por exemplo, no caso de um arquivo excluído).

Geralmente, é uma péssima ideia usar qualquer informação obtida dessa maneira. Se alguém chamar seu script com a saída redirecionada para um arquivo, ele não vai gostar se você se comportar de maneira diferente por causa da localização do arquivo ou afetar o arquivo de outras maneiras que não sejam anexá-lo a ele. Há uma exceção: você pode querer reagir de forma diferente, dependendo de estar escrevendo para um terminal ou para outra coisa (canal, soquete, arquivo), por exemplo, para exibir cores ou indicadores de progresso em um terminal. Existe um teste específico para determinar se um descritor de arquivo está conectado a um terminal:

if [ -t 2 ]; then
  # stderr is a terminal
  printf 1>&2 '\e[31mError: widget not found\e[0m'
else
  # stderr is not a terminal
  echo 1>&2 'Error: widget not found'
fi
    
por 07.04.2014 / 22:59
5
{ readlink /dev/fd/[1,2] ; echo "out" ; } >./file 2>./error    
{ readlink /dev/fd/0 ; cat ; } <./file

OUTPUT:

/home/mikeserv/file
/home/mikeserv/file
/home/mikeserv/error
out

{ readlink /proc/$$/fd/[1,2] ; echo out ; } >./file 2>./error
{ readlink /proc/$$/fd/0 ; cat ; } <./file

OUTPUT:

/home/mikeserv/file
/home/mikeserv/file
/home/mikeserv/error    
out
    
por 07.04.2014 / 10:46
0

No seu caso, STDOUT será salvo no arquivo output.log e STDERR será salvo no arquivo error.log . Ambos os arquivos são salvos no mesmo diretório com script.sh .

Se você quiser que seu programa "saiba o caminho para esses arquivos", você deve usar o caminho absoluto:

./script.sh > /path/to/output.log 2> /path/to/error.log
    
por 07.04.2014 / 10:33
0

Os arquivos output.log e error.log são criados no diretório atual, ou seja, o valor da variável $PWD . Se você quiser que seu programa use esses arquivos mais tarde, salve o diretório deles em uma variável antes de executar o script. Aqui está um exemplo:

OUTDIR=$PWD
./script.sh 1> output.log 2> error.log
# Whatever you want to do else ...
echo The output file : =======
cat $OUTDIR/output.log
echo =========================
echo 
echo The errors file : =======
cat $OUTDIR/error.log
echo =========================
    
por 07.04.2014 / 10:56