Como agrupar comandos canalizados para processar com uma função de invólucro

3

Estou tentando me escrever uma função de logging para o meu shell bash. Meu objetivo é ter a função que pode iniciar um comando e passar o stdout e stderr do comando para arquivos de log datados. Atualmente tenho:

logme()
{
    FULL_COMMAND=$@

    for EXE in ${FULL_COMMAND}
    do
        case $EXE in
            nohup) continue;;
            time) continue;;
        esac
        break
    done

    mkdir -p logs
    LOGNAME=$(basename ${EXE})_$(date +%Y-%m-%d_%H:%M:%S)

    echo $FULL_COMMAND > logs/${LOGNAME}.e.log
    echo '============' >> logs/${LOGNAME}.e.log
    $FULL_COMMAND > logs/${LOGNAME}.o.log 2>> logs/${LOGNAME}.e.log
}

Isso parece funcionar para casos simples. Executando:

$ touch file1.txt
$ touch file2.txt
$ touch file3.txt

$ logme ls -lh

produz um diretório de logs com 2 arquivos datados.

$ more logs/ls_2017-05-08_16\:05\:36.e.log 
ls -lh
============

$ more logs/ls_2017-05-08_16\:05\:36.o.log 
total 6.5K
-rw-r--r-- 1 aholman compbio  0 May  8 16:05 file1.txt
-rw-r--r-- 1 aholman compbio  0 May  8 16:05 file2.txt
-rw-r--r-- 1 aholman compbio  0 May  8 16:05 file3.txt
drwxr-xr-x 2 aholman compbio 92 May  8 16:05 logs

No entanto, a adição de pipes no comando não se comporta como eu esperava. O registro parece agrupar com o primeiro comando, e a saída do logme é passada através da tubulação. Naturalmente, não há saída do logme porque todo o propósito é direcioná-lo para arquivos.

$ logme ls -lh | grep -v file2
$ more logs/ls_2017-05-08_16\:12\:15.e.log 
ls -lh
============

$ more logs/ls_2017-05-08_16\:12\:15.o.log 
total 6.5K
-rw-r--r-- 1 aholman compbio  0 May  8 16:05 file1.txt
-rw-r--r-- 1 aholman compbio  0 May  8 16:05 file2.txt
-rw-r--r-- 1 aholman compbio  0 May  8 16:05 file3.txt
drwxr-xr-x 2 aholman compbio 92 May  8 16:12 logs

Existe uma boa maneira de agrupar todo o comando de modo que a coisa toda seja processada pelo log-me?

    
por A Holman 08.05.2017 / 22:59

1 resposta

2

O shell está processando a linha de comando antes que seu script a veja. Só passa o que resta depois desse processamento (esse comando antes do pipe). Para contornar tal processamento você precisa citar todo o comando:

logme 'ls -lh | grep -v file2'

Você tem um novo problema. O comando está em uma string e você não pode executá-lo diretamente. Uma maneira de fazer isso é com eval

eval "$FULL_COMMAND" > logs/${LOGNAME}.o.log 2>> logs/${LOGNAME}.e.log

Mas o eval deve ser usado com cuidado, pois é facilmente explorável: link

    
por 03.06.2017 / 19:02

Tags