tar para canalizar, mas mantenha a saída detalhada -v separada de STDERR


12

Um comando tar normal

tar cvf foo.tar ./foo >foo.out 2>foo.err

possui três fluxos de E / S de saída

  • arquivar dados no foo.tar
  • lista de nomes de arquivos para STDOUT (redirecionada para foo.out)
  • mensagens de erro para STDERR (redirecionadas para foo.err)

Posso inspecionar o foo.err em busca de mensagens de erro sem precisar ler a lista de nomes de arquivos.

se eu quiser fazer alguma coisa com os dados do arquivo (canalizá-lo através do netcat ou de um programa de compactação especial), posso usar a -f -opção tar

tar cvf - ./foo 2>foo.err | squish > foo.tar.S

Mas agora minha lista de nomes de arquivos está misturada às minhas mensagens de erro, porque a -vsaída do tar obviamente não pode ir para STDOUT (é para onde os dados do arquivo fluem), então o tar habilmente escreve isso no STDERR.

Usando o shell Korn, existe uma maneira de construir um comando que canaliza o fluxo de archive para outro comando, mas ainda captura a -vsaída separadamente de qualquer mensagem de erro.


Você está familiarizado tee? Parece um caso de uso bastante válido para isso.
precisa saber é o seguinte

Respostas:


9

Se o seu sistema suportar /dev/fd/n:

tar cvf /dev/fd/3 ./foo 3>&1 > foo.out 2>foo.err | squish > foo.tar.S

Quais com as implementações da AT&T de ksh(ou bashou zsh) você pode escrever usando a substituição de processo :

tar cvf >(squish > foo.tar.S) ./foo > foo.out 2>foo.err

Isso está fazendo exatamente a mesma coisa, exceto que desta vez, o shell decide qual descritor de arquivo usar em vez de 3(normalmente acima de 9). Outra diferença é que desta vez, você obtém o status de saída em tarvez de squish. Em sistemas que não suportam /dev/fd/n, alguns shells podem recorrer a pipes nomeados para esse recurso.

Se seu sistema não suportar /dev/fd/nou seu shell não puder usar pipes nomeados para sua substituição de processo, é aí que você terá que lidar com pipes nomeados manualmente .


6

Você precisa usar um pipe nomeado para isso.

Primeiro, crie um na pasta:

mkfifo foo.pipe

Em seguida, use esse comando:

tar cvf foo.pipe ./foo >foo.out 2>foo.err & cat foo.pipe >foo.tar

Observe: a catparte-agora também pode ser gzipou seja o que for, que pode ler de um tubo:

tar cvf foo.pipe ./foo >foo.out 2>foo.err & gzip -c foo.pipe >foo.tar

Explicação:

O resultado é enviado para o tubo de nome ( foo.pipe), onde outro proccess ( cat, gzip, netcat) lê. Portanto, você não perde os canais stdout / stderr para obter informações.


1
Pode valer a pena observar as implicações do uso de pipes nomeados . 1) o melhor é definir um umask 077(ou usar um diretório temporário privado) para impedir que outros processos sejam lidos ou gravados nele (em muitos sistemas, pipes nomeados, como outros arquivos são criados legíveis pelo mundo por padrão), 2) você precisa garantir o pipe nomeado é usado apenas por cada instância do seu script (novamente, um diretório temporário privado único ajuda) 3) Isso significa que você precisa fazer a limpeza posteriormente ou se for interrompido.
Stéphane Chazelas

1
+1 - Gostei desta resposta. Infelizmente para mim, há alguma estranheza nos pipes nomeados no meu sistema (antigo) que os torna não confiáveis ​​quando eu tento isso.
precisa saber é o seguinte

1
@ StéphaneChazelas - Eu acho que às vezes pode ser mais fácil de limpar primeiro, como:p="/tmp/pipe$$"; mkfifo "$p"; (read na; cmd[s]...) <>"$p" & (echo;rm "$p"; cmd[s]...) >"$p"
mikeserv

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.