Um programa que pode armazenar em buffer stdin ou arquivo

12

Além de usar um arquivo temporário para ajudar, existe uma maneira / programa de armazenar em buffer a entrada, stdinmas não produz o conteúdo até obter o arquivo EOF. Também não quero usar uma variável de shell (por exemplo buffer=$(cat)).

Este programa deve se comportar da seguinte forma (suponha que o nome do programa seja buffered-cat):

$ buffered-cat
line 1
line 2
line 3
^D # Ctr-D here(End of Line)

Agora que o programa recebeu ^D, o buffered-catresultado é gerado

line 1
line 2
line 3
Ekeyme Mo
fonte
Eu normalmente uso sortpara esse fim. Obviamente, tem efeitos colaterais que podem ser indesejáveis.
Adrian Pronk

Respostas:

20

Um homem pobre spongeusando awk:

awk '{a[NR] = $0} END {for (i = 1; i <= NR; i++) print a[i]}'

Se você tiver tac, também poderá usá-lo incorretamente:

... | tac | tac
muru
fonte
1
tacé simples e elegante, eu acho.
Ekeyme Mo
6
O @EkeymeMo | tac | tac é simples, mas lembre-se de que é altamente ineficiente para a tarefa e você sofrerá um impacto no desempenho, especialmente em arquivos maiores.
Digital Trauma
@DigitalTrauma sim, eu sei a desvantagem disso. Eu testei um arquivo com 100 mil linhas. Está tudo bem para mim. Votei seu comentário como é verdade.
Ekeyme Mo
29

Você pode fazer isso com o spongemoreutils . sponge"absorverá a entrada padrão e gravará em um arquivo". Sem argumentos, esse arquivo é uma saída padrão. A entrada fornecida para este comando é armazenada na memória até EOF e, em seguida, gravada de uma só vez.

Para gravar em um arquivo normal, você pode apenas dar o nome do arquivo:

cmd | sponge filename

O principal objetivo de spongeé permitir a leitura e gravação do mesmo arquivo em um pipeline, mas ele também faz o que você deseja.

Michael Homer
fonte
6

Desde que sua entrada seja texto ASCII (não contém NUL 0x0 bytes até o final), sed -zfaça o que deseja:

$ sed -z ''
Line 1
Line 2
Line 3
^D
Line 1
Line 2
Line 3
$ 

As -zcausas sedpara tratar o byte NUL como um delimitador de linha em vez da nova linha usual. Portanto, desde que sua entrada seja texto normal sem bytes NUL, o sed continuará lendo toda a entrada em seu buffer de padrão até que o EOF seja alcançado. sedentão não processa o buffer e o produz.


Se houver NUL bytes em sua entrada, você poderá fazer isso:

sed ':l;N;bl'
Trauma Digital
fonte
4

Essa sedsolução é um pouco mais longa que a do DigitalTrauma, mas também funciona com bytes NUL.

sed -n 'H;${x;s/^\n//;p}'
JoL
fonte
2
sed ':l;N;bl'deve funcionar também.
Digital Trauma
1

O comportamento que você está pedindo, não é o comportamento padrão do gato simples?

gv@debian:$ cat << EOF #or cat <<EOF >file or cat <<EOF >/dev/stdout
> Line 1
> Line 2
> Line 3
> EOF
Line 1
Line 2
Line 3
gv@debian:$
George Vasiliou
fonte
3
Não, esse é o comportamento dos documentos aqui. Tente digitar cat(Enter) Line 1(Enter) e veja o que acontece.
G-Man diz 'Reinstate Monica'
Sim, essa é a estrutura aqui-doc. Simples e aproxima-se bastante do que o OP quer.
Também
1

Mesma idéia do exemplo awk de muru, exceto em Python. Use CtrlDpara parar de ler nas linhas

$ python -c 'import sys;print("".join(sys.stdin.readlines()))'                                                           
line1
line2
line3 # press Enter and Ctrl+D at this point
line1
line2
line3
Sergiy Kolodyazhnyy
fonte
2
Ou perl -e 'print <>'(!)
dave_thompson_085 15/01