você está aqui: Home  → Arquivo de Mensagens

Redirecionamentos - Parte 5 - Como um script recebe dados pela StdIn

Colaboração: Julio Cezar Neves

Data de Publicação: 05 de outubro de 2019

IMPORTANTE: As inscrições para a última turma do ano do curso Programação Shell Linux do Prof. Julio Neves se esgotam em breve, no dia 7 de outubro, às 23h59m. Clique aqui para saber mais e reservar a sua vaga.


Nessa série de artigos sobre redirecionamento, já foram mostrados diversos macetes dentre os quais destaco a forma de se mandar uma mensagem para a saída de erros (StdErr) e não para a tela, como é comum (mas incorreto) vermos.

Complementando isso hoje veremos o que se deve fazer para nosso script receber dados pela entrada primária ou pelas áreas de transferência.

Como saber se existe algo na entrada primária

Testamos a entrada primária com a opção -t 0 do comando test, que será verdadeira se não houver dado em StdIn. A opção -t é para testar file descriptors (que analisamos nos 4 artigos anteriores) e zero (0) é o file descriptor padrão da entrada primária (StdIn).

Sabemos que comandos no interior de parênteses criam um subshell para a execução, como se formassem um script, então para demonstrar o uso do test com exemplos curtos, usarei esta técnica para emular scripts. Para começar, veja isso:

$ ([[ -t 0 ]] && echo StdIn vazia || echo Existem dados em StdIn)
StdIn vazia

Essa linha de comandos deve ser entendida como: se não houver dados em StdIn imprima StdIn vazia, caso contrário Existem dados em StdIn. Como não pusemos nada na entrada, funcionou do jeito que queríamos.

Então vamos mandar dados via pipe (|):

$ echo Uma frase | ([[ -t 0 ]] && echo StdIn vazia || echo Existem dados em StdIn)
Existem dados em StdIn

Passando dados via Here Strings e recuperando-os:

$ ([[ -t 0 ]] && echo StdIn vazia || echo "$(cat -)" está em StdIn) <<< "A B C"
A B C está em StdIn

E o mesmo valeria se tivéssemos um arquivo na entrada:

$ cat x
Linha1 de teste
Linha2 de teste

$ ([[ -t 0 ]] && echo StdIn vazia || echo "$(cat -)" está em StdIn) < x
Linha1 de teste
Linha2 de teste está em StdIn

Já vimos o conteúdo do arquivo x agora veja isso:

$ echo Linha0 de teste | cat - x
Linha0 de teste
Linha1 de teste
Linha2 de teste

Ou com Here Strings:

$ cat - x <<< "Linha0 de teste"
Linha0 de teste
Linha1 de teste
Linha2 de teste

Ou seja, o cat - lista tudo o que vem da entrada primária e foi por isso que usamos o $(cat -) no nosso exemplo. Essa construção agregaria os parâmetros recebidos, antes de imprimir a linha.

O test -t FDn serve para qualquer file descriptor independente do inteiro em FDn. Vamos brincar com a saída de erros (FDn = 2). Suponha que eu queira mandar uma mensagem para a saída de erros e em seguida dar um read para que o usuário confirme ter lido a mensagem. Seria assim:

$ (echo Deu erro >&2; read)
Deu erro

Aparentemente funcionou, pois deu a mensagem e ficou esperando um <ENTER> mas e se a saída for redirecionada para um arquivo, para /dev/null ou for trancada (2>&-)? Nesses casos não haveria nenhuma mensagem mas o programa ficaria parado esperando um <ENTER>. Então o correto seria se só fizéssemos o read se não houvesse desvio na StdErr. Ficaria assim:

$ (echo Deu erro >&2; [[ -t 2 ]] && read)

Dessa maneira, em qualquer dos casos descritos acima, ele não daria a mensagem nem executaria o read. Experimente. Consolidando tudo que vimos até aqui nessa série de artigos, vou te mostrar uma forma de pegar o dado de entrada por qualquer meio que ele venha. Aconselho entendê-lo e, se quiser, transformá-lo em uma função para usar em seus scripts.

$ cat test_stdin.sh
#!/bin/bash
#
# Para saber se tem dado na entrada primária
#
if [[ -t 0 ]]       # Verdadeiro se não houver dados em StdIn
then
    if (($# == 0))  # Então testa se foram passados parâmetros
    then
        echo Não tem dados na StdIn nem parâmetros >&2
        exit 1
    fi
    Meio="por passagem de parâmetros" # Como os dados vieram?
else
    Parms=$(cat -)         # O que veio pela StdIn vai para $Parms 
    set "$Parms"           # Os dados de Parms viram parâmetros posicionais
    Meio="pela entrada primária"      # Como os dados vieram?
fi
echo -e "Recebi $Meio os seguintes dados:\n$@"

No próximo e último artigo deste séria mostrarei como mandar/receber dados para/de as áreas de transferência



Veja a relação completa dos artigos de Julio Cezar Neves