Como escrever um script que pode receber entrada de stdout

1

Eu quero ser capaz de escrever um script que possa usar stdout como argumento, se algo for canalizado para ele (em última análise, eu gostaria que ele fosse polimórfico) -

O problema é que pesquisei e procurei como fazer isso sem sucesso - muitas sugestões alternativas sobre como fazer outras coisas que não são - isso:

cat /var/log/some.log | grep something | awk '{print $1 $6 $8}' | myscript

Por que isso, em vez de? : myscript $(!!) Neste ponto, apenas para provar que é possível ...

Eu sei que você pode 'ler variável' em um script, mas diga que eu não me importo com as falas - digamos, eu quero aceitar tudo isso como uma bolha de texto e fazer algo com isso no script -

Eu realmente preciso:

while read x; do
stdin=$stdin" "$x;
done;

unicamente para ler a partir de STDIN?

Deve haver uma maneira melhor ...

    
por rm-vanda 02.07.2015 / 01:01

3 respostas

2

Se você quiser ler todo o stdin em um script de shell, normalmente você o captura em um arquivo temporário:

TMPFILE=$(mktemp /tmp/$0.$$.XXXXXX)
cat > "$TMPFILE"
# Script works with $TMPFILE and its contents,
# ultimately writing everything to stdout.
rm -f "$TMPFILE"

Até os utilitários do sistema fazem coisas muito parecidas com isso. sort tem que ter todos os stdin antes de poder imprimir qualquer coisa para stdout, por exemplo.

    
por 02.07.2015 / 05:57
3

Você pode ler a partir do stdout redirecionando a entrada do descritor de arquivo 1. O Stdout é o descritor de arquivo 1 por definição. O fato de o descritor de arquivo 1 ser usado para saída é uma questão de convenção, não uma obrigação técnica. No entanto, é uma coisa bizarra de se fazer, o que confunde as pessoas que usam o seu script.

read line <&1

Se você quiser ler um arquivo inteiro, use cat . Para colocar o conteúdo em uma variável, use uma substituição de comando.

whole_input=$(cat)
whole_input_from_stdout=$(cat <&1)

Alguns shells permitem que você escreva $(</dev/stdin) como um atalho um pouco mais eficiente para $(cat) .

Observe que isso cria novas linhas. Esse comportamento é construído em substituição de comando. Para reter novas linhas, esconda-as atrás de outro personagem e remova-o.

whole_input=$(cat; echo .); whole_input=${whole_input%?}

A variável shell conterá apenas os dados até o primeiro byte nulo, se houver um byte nulo na entrada. Com alguns shells, você obterá todos os dados com os bytes nulos removidos. Shells não podem lidar com dados binários. Zsh é uma exceção, ele retém os bytes nulos.

    
por 02.07.2015 / 09:31
2

Você não precisa obter o nódulo inteiro se não quiser - pode dividir o stdin e trabalhá-lo como um fluxo, se quiser. No entanto, eu fiz algumas pesquisas no Google e acho que não posso oferecer nenhum conselho sobre como mudar o sexo do seu script, ou seja o que for que você quis dizer com polimórfico .

Em qualquer caso, eu normalmente acho que colocar toda a entrada de lado em algum armazenamento raramente é o que eu estou procurando. Eu geralmente quero lidar com isso em pedaços delimitados de algum tipo. Aqui está um exemplo de como você pode obter entradas de qualquer tipo divididas em blocos de 4k por% iteração de ciclowhile:

splitin(){
    dd obs=4k | { j=$1 f=$2;shift 2 && 
    while dd bs=4k count=1 of="$f"  &&
          [ -s "$f" ] 
    do    "$j" "$@" < "$f"
    done
};  }

... que é uma função que você pode chamar do seu shell script com o nome de um trabalho que você deseja executar em intervalos de entrada de 4k e o nome de um arquivo temporário que pode ser usado para armazenar cada último fragmento. Como:

splitin handle_chunk /tmp/work/chunk \
        other args to pass on as appropriate   
    
por 02.07.2015 / 11:29