Como redirecionar o stderr em uma variável, mas mantenha o stdout no console [duplicado]

1

Meu objetivo é chamar um comando, obter stderr em uma variável, mas manter stdout (e somente stdout) na tela. Sim, isso é o oposto do que a maioria das pessoas faz:)

No momento, o melhor que eu tenho é:

#!/bin/bash
pull=$(sudo ./pull "${TAG}" 2>&1)
pull_code=$?

if [[ ! "${pull_code}" -eq 0 ]]; then
  error "[${pull_code}] ${pull}"
  exit "${E_PULL_FAILED}"
fi

echo "${pull}"

Mas isso só pode mostrar o stdout em caso de sucesso e após o término do comando. Eu quero ter stdout ao vivo, isso é possível?

EDITAR

Obrigado a @sebasth e com a ajuda de Redirecionar STDERR e STDOUT para diferentes variáveis sem arquivos temporários , eu escrevo isto:

#!/bin/bash
{
  sudo ./pull "${TAG}" 2> /dev/fd/3
  pull_code=$?
  if [[ ! "${pull_code}" -eq 0 ]]; then
    echo "[${pull_code}] $(cat<&3)"
    exit "${E_PULL_FAILED}"
  fi
} 3<<EOF
EOF

Eu admito que isso não é realmente "bonito", parece complicado, e eu realmente não entendo porque o heredoc é necessário ...

Esta é a melhor maneira de conseguir isso?

    
por Doubidou 09.10.2018 / 10:46

4 respostas

2

Use apenas:

{ err=$(cmd 2>&1 >&3 3>&-); } 3>&1

Para obter o stderr de cmd deixando seu stdout intocado (aqui usando fd3 para trazer o stdout original (copiado com 3>&1 ) dentro da substituição do comando (restaurado com >&3 depois de ter redirecionado o fd 2 para o pipe criado pela substituição do comando com 2>&1 )).

    
por 09.10.2018 / 11:42
2

Você pode usar a resposta fornecida por Stéphane Chazelas com pequenas modificações: somente redirecionar stderr e não usar o comando substituição para executar o seu comando.

{
  command 2> /dev/fd/3
  res=$?
  err=$(cat<&3)
} 3<<EOF
EOF

printf 'stderr: %s\n' "$err"

A saída de command será normalmente em stdout e stderr é em err variable.

    
por 09.10.2018 / 11:19
0

Apenas troque stdout e stderr pelo comando para capturar stderr.

pull=$(sudo ./pull "${TAG}" 3>&2 2>&1 1>&3)

E então redirecione o stderr de volta ao stdout:

{ pull=$(sudo ./pull "${TAG}" 3>&2 2>&1 1>&3; } 2>&1

Explicação:

Da mesma forma que quando você captura somente stdout de um comando:

var=$(cmd)

a saída do stderr ainda vai para a linha de comando. Você pode trocar os dois canais para capturar apenas o stderr:

var=$(cmd 3>&2 2>&1 1>&3)

E então, redirecione o stderr de volta para stdout (para mostrar a saída (se houver)).

{ var=$(f 3>&2 2>&1 1>&3); }  2>&1
    
por 09.10.2018 / 11:50
0

Combinando respostas de ambas Como enviar para a tela o redirecionamento de substituição e Como capturar stderr de um bash palavra-chave (por exemplo, tempo)? , eu recebo

var=$( (cmd >/dev/tty) 2>&1)

Se você não estiver usando um código ou palavra-chave, isso simplifica para

var=$( cmd 2>&1 >/dev/tty )
    
por 09.10.2018 / 12:04