Como compor as funções bash usando pipes?

16

Eu tenho poucas funções definidas desta maneira:

function f {
  read and process $1
  ...
  echo $result
}

Eu quero compô-los juntos para que a invocação se pareça com f | g | h .

Qual idioma devo usar para converter a função trabalhando em argumentos para um dos argumentos de leitura do stdin? É possível ler pares, tuplas de argumentos do fluxo sem necessidade de escapar deles (por exemplo, terminação nula)?

    
por Rumca 08.02.2014 / 01:18

2 respostas

18

Uma abordagem potencial seria colocar uma construção while...read dentro de suas funções, que processaria quaisquer dados que entrassem na função através de STDIN, operariam sobre ela e, em seguida, emitiriam os dados resultantes de volta via STDOUT.

function X {
  while read data; do
    ...process...
  done
}

O cuidado precisará ser gasto com a configuração dos componentes while ..read.. , pois eles dependerão muito dos tipos de dados que poderão consumir de forma confiável. Pode haver uma configuração ideal que você possa criar.

Exemplo

$ logF() { while read data; do echo "[F:$(date +"%D %T")] $data"; done; }
$ logG() { while read data; do echo "G:$data";                    done; }
$ logH() { while read data; do echo "H:$data";                    done; }

Aqui está cada função por si só.

$ echo "hi" | logF
[F:02/07/14 20:01:11] hi

$ echo "hi" | logG
G:hi

$ echo "hi" | logH
H:hi

Aqui estão quando os usamos juntos.

$ echo "hi" | logF | logG | logH
H:G:[F:02/07/14 19:58:18] hi

$ echo -e "hi\nbye" | logF | logG | logH
H:G:[F:02/07/14 19:58:22] hi
H:G:[F:02/07/14 19:58:22] bye

Eles podem ter vários estilos de entrada.

#-- ex. #1
$ cat <<<"some string of nonsense" | logF | logG | logH
H:G:[F:02/07/14 20:03:47] some string of nonsense

#-- ex. #2    
$ (logF | logG | logH) <<<"Here comes another string."
H:G:[F:02/07/14 20:04:46] Here comes another string.

#-- ex. #3
$ (logF | logG | logH)
Look I can even
H:G:[F:02/07/14 20:05:19] Look I can even
type to it
H:G:[F:02/07/14 20:05:23] type to it
live
H:G:[F:02/07/14 20:05:25] live
via STDIN
H:G:[F:02/07/14 20:05:29] via STDIN
..type Ctrl + D to stop..

#-- ex. #4
$ seq 5 | logF | logG | logH
H:G:[F:02/07/14 20:07:40] 1
H:G:[F:02/07/14 20:07:40] 2
H:G:[F:02/07/14 20:07:40] 3
H:G:[F:02/07/14 20:07:40] 4
H:G:[F:02/07/14 20:07:40] 5

#-- ex. #5
$ (logF | logG | logH) < <(seq 2)
H:G:[F:02/07/14 20:15:17] 1
H:G:[F:02/07/14 20:15:17] 2
    
por 08.02.2014 / 02:07
4

Como um adendo à resposta do slm , fiz algumas experiências com tuplas separadas por nulos como argumentos de função:

$ sayTuple() { 
    IFS= read -r -d $'
$ printf "%s
$ sayTuple() { 
    IFS= read -r -d $'
$ printf "%s%pre%%s%pre%" "Hello " $' Brave\n\tWorld' | sayTuple 
sayTuple: -Hello - - Brave
        World-
' d1 IFS= read -r -d $'%pre%' d2 echo "sayTuple: -$d1- -$d2-" }
%s%pre%" "Hello " $' Brave\n\tWorld' | sayTuple sayTuple: -Hello - - Brave World-
' d1 IFS= read -r -d $'%pre%' d2 echo "sayTuple: -$d1- -$d2-" }

Notas: sayTuple duas vezes lê um registro com terminação nula -d $'IFS=' manipulando qualquer espaço em torno da entrada echo . - back records cercados por \n

O resultado mostra que ele manipula corretamente a entrada com terminação nula contendo \t e %code% :

%pre%

Por favor, adicione sugestões para melhorias nos comentários, é um tópico interessante.

    
por 08.02.2014 / 12:43