Como posso redirecionar a saída de um processo filho?

2

Estou executando o seguinte comando git clone por meio de sudo e bash e quero redirecionar o STDOUT para um arquivo de log:

% sudo -u test_user bash -c "git clone https://github.com/scrooloose/nerdtree.git
/home/test_user/.vim/bundle/nerdtree >> /var/log/build_scripts.log"

O que está acontecendo é que o STDOUT continua a ser enviado para o terminal. ou seja,

Cloning into 'nerdtree'...
remote: Counting objects: 3689, done.
[...]
Checking connectivity... done.

Eu estou supondo que o problema tem algo a ver com o fato de que sudo está forking um novo processo então bash está forking outro, como demonstrado aqui:

% sudo -u test_user bash -c "{ git clone https://github.com/scrooloose/nerdtree.git
/home/test_user/.vim/bundle/nerdtree >> /var/log/build_scripts.log; ps f -g$$; }"  

  PID TTY      STAT   TIME COMMAND
 6556 pts/25   Ss     0:02 /usr/bin/zsh
 3005 pts/25   S+     0:00  \_ sudo -u test_user bash -c { git clone https://github.com/scrooloo
 3006 pts/25   S+     0:00      \_ bash -c { git clone https://github.com/scrooloose/nerdtree.
 3009 pts/25   R+     0:00          \_ ps f -g6556

Eu tentei

  • executando isso em um script e usando exec >> /var/log/build_script.log antes do comando
  • envolvendo o comando em uma função e, em seguida, chamando e redirecionando as funções output

Mas acho que esses redirecionamentos só estão se aplicando ao pai e os processos filhos estão padronizando o envio de STDOUT para o /dev/tty/25 de seu pai, fazendo com que a saída continue para o terminal.
Como posso redirecionar o STDOUT deste comando?

    
por the_velour_fog 27.04.2016 / 10:18

2 respostas

10

As mensagens mencionadas não são impressas na saída padrão, mas no erro padrão. Portanto, para capturá-los, você precisa redirecionar o erro padrão em vez da saída padrão:

sudo -u user bash -c "git clone https://github.com/foo.git ~/foo 2>> log"

Ou tanto STDERR quanto STDOUT:

sudo -u user bash -c "git clone https://github.com/foo.git ~/foo >> log 2>&1"

Com bash , você também pode usar &>> para isso:

sudo -u user bash -c "git clone https://github.com/foo.git ~/foo &>> log"

O csh , tcsh , zsh equivalente é >>& ( (t)csh não suporta 2>&1 , por isso é o único caminho):

sudo -u user csh -c "git clone https://github.com/foo.git ~/foo >>& log"

Em fish

sudo -u user fish -c "git clone https://github.com/foo.git ~/foo >> log ^&1"

Para saber mais sobre os diferentes tipos de operadores de redirecionamento, consulte Quais são os operadores de controle e redirecionamento do shell?

Agora, no caso específico de git , há outro problema. Como alguns outros programas, git pode detectar que sua saída está sendo redirecionada e interrompe a impressão de relatórios de progresso em caso afirmativo. Provavelmente, isso ocorre porque os relatórios devem ser vistos ao vivo e incluem \r , que pode ser um problema quando salvo em um arquivo. Para contornar isso, use:

       --progress
       Progress status is reported on the standard error stream by default
       when it is attached to a terminal, unless -q is specified. This
       flag forces progress status even if the standard error stream is
       not directed to a terminal.

E:

sudo -u user bash -c "git clone --progress https://github.com/foo.git ~/foo >> log 2>&1"

Se você quer ver a saída como ela vem e salvar em um arquivo, use tee :

sudo -u user bash -c "git clone --progress https://github.com/foo.git ~/foo 2>&1 | 
    tee -a log
    
por 27.04.2016 / 10:32
1
git clone https://github.com/scrooloose/nerdtree.git
/home/test_user/.vim/bundle/nerdtree &>> /var/log/build_scripts.log
    
por 27.04.2016 / 10:23