Processo de substituição com tee e colar

6

Eu estou tentando canalizar um comando através da saída de dois outros comandos e, em seguida, mesclar os resultados das duas substituições de processo. Um exemplo que me aproxima é:

command | tee >(sed -rn 's/.*foo (bar).*/1/p') >(awk '{print $3}')

No entanto, gostaria de alcançar o seguinte:

  • Eu não preciso ver o fluxo de entrada do comando original
  • Gostaria de usar 'colar' para mesclar os resultados

Suponho que uma opção é executar dois comandos separados e colocá-los em arquivos, mas isso não é tão elegante quanto eu gostaria. Qual é a maneira mais elegante (single liner, claramente entendida) de fazer isso em bash?

    
por Arima 11.06.2014 / 01:51

2 respostas

8

O motivo pelo qual você está vendo a saída do comando original é porque tee retorna para stdout , assim como os arquivos especificados. Para descartar isso, você pode colocar >/dev/null no final do comando ou redirecionar essa saída para uma das suas substituições de processo adicionando um > extra, por exemplo:

command | tee >(sed -rn 's/.*foo (bar).*/1/p') > >(awk '{print $3}')

Ou mais simples, basta usar outro canal:

command | tee >(sed -rn 's/.*foo (bar).*/1/p') | awk '{print $3}'

Quanto a combinar o resultado das duas substituições de processo usando paste , a menos que haja algum truque de shell obscuro que eu não saiba, não há como fazer isso sem usar um pipe nomeado. Em última análise, são duas linhas (formatadas para mais para clareza):

mkfifo /tmp/myfifo
command |
  tee >(sed -rn 's/.*foo (bar).*/1/p' >/tmp/myfifo) |
  awk '{print $3}' |
  paste /tmp/myfifo -

Se você está colocando isso em um script, considere também usar as recomendações para criar um canal nomeado temporário aqui .

    
por 11.06.2014 / 21:04
3

Você pode fazer tudo isso apenas em sed .

command | 
sed '/\([^ ][^ ]*  *\)\{2\}/{h
         s///;s/^  *//;s/ .*/p
     g};s/.*foo \(bar\).*//p;d'  

Mas quanto à outra coisa, você tem tee ao redor dos arquivos |pipe :

cmd1 | {     
    {   tee /dev/fd/3 | 
        cmd2 >&2
    } 3>&1 | 
    cmd3
} 2>&1 |paste

Mas, como você já usa o sed , pode usá-lo como um smart tee e somente o dup / redirect quando precisar:

cmd | { 
    sed -n 'p;s/.*foo \(bar\).*//w /dev/fd/3' |
    awk ...
} 2>&1
    
por 11.06.2014 / 22:11