Como um script bash pode escrever sua saída padrão de dentro de um pipeline? [duplicado]

3

Eu tenho um script bash que chama uma função. A função, entre outras coisas, executa um pipeline que afunda sua saída. Para simplificar, aqui está um exemplo inventado:

#!/bin/bash
func() {
  ls "$@" | sort | rev > /tmp/output
}
func "$@"

Você faria algo assim para executá-lo. Ele faria suas coisas e entregaria sua carga para um arquivo. Não há saída para a tela.

$ ./myscript .

Agora, digamos que eu queira a saída de sort na saída padrão. Como eu faria isso?

Eu posso consegui-lo assim:

ls "$@" | sort | tee /dev/tty | rev > /tmp/output

No entanto, usar /dev/tty está errado, porque isso não funcionará:

$ ./myscript > myfile

Existe uma maneira mais correta de se referir à saída padrão de um script bash de dentro de uma pipleine dentro de uma função?

(Estou usando o bash 4.3.0 no Arch Linux)

    
por starfry 16.10.2014 / 15:57

2 respostas

4

A maneira mais simples de pensar nisso é:

ls "$@" | sort | tee >(rev > /tmp/output)

O tee enviará uma cópia para STDOUT e, como não há mais | , ela será herdada, o que significa que ela será enviada para o TTY, se não for redirecionada, e seu myfile se é.
A outra cópia será enviada para rev > /tmp/output em seu STDIN. No bash, >(...) executa o que estiver entre os parênteses e, em seguida, substitui o >(...) pelo caminho para um canal conectado ao seu STDIN.

    
por 16.10.2014 / 16:44
2

Como a outra resposta não está sendo clara sobre isso, o outro (outro) caminho é

exec 3>&1
ls | sort | tee /dev/fd/3 | rev > /tmp/output

O exec 3>&1 dup licates descritor de arquivo 1 (stdout) como descritor de arquivo 3. Em seguida, tee /dev/fd/3 grava uma cópia da saída de sort nesse descritor de arquivo. Isso deve funcionar em qualquer shell, mas pode depender do sistema operacional. Uma variante que deve ser independente do sistema operacional, mas é bash -specific é:

exec 3>&1
ls | sort | tee >( cat >&3 ) | rev > /tmp/output

Em bash , >(command) fornece um identificador de arquivo para um pipe para um processo executando command . Em qualquer shell (?), command >&fd executa command com seu stdout redirecionado para o descritor de arquivo especificado, que deve ter sido previamente estabelecido.

Uma versão mais complicada, que deve funcionar em qualquer sistema * nix (Posix), é

pipe_to_stdout=$(mktemp -u)
mkfifo "$pipe_to_stdout"
cat "$pipe_to_stdout" &
ls | sort | tee "$pipe_to_stdout" | rev > /tmp/output
rm "$pipe_to_stdout"

que é praticamente o mesmo que o segundo exemplo (o cat lê o fifo e escreve para stdout), mas usando menos fumaça e espelhos no nível da casca.

Note que estas respostas são flexíveis em que você poderia escrever a saída do ls para a saída padrão apenas reorganizando os comandos.

    
por 16.10.2014 / 18:58