Буфериране на редове в bash coproc

Опитвам се да използвам bash coproc и аз Срещам затруднения, най-вероятно с буферирането. Имам сложна команда, която приема редово-ориентиран вход от stdin и отпечатва ред в stdout, на входен ред. В командния ред тази команда работи добре на базата на ред, но когато я поставя в coproc и чета от ${COPROC[0]} FD, четенето блокира.

Мога да пресъздам това поведение с paste, но не и с cat. Очаквам paste и cat да направят почти същото, когато не са подадени параметри. Такъв е случаят, когато стартирате директно от командния ред:

$ cat
Hello World!<RETURN>
Hello World!^D
$ paste
Hello World!<RETURN>
Hello World!^D
$ 

(RETURN и ^D добавени за илюстрация)

Но когато ги поставя в coproc, те се държат по различен начин - cat е строго буфериран в редове, докато paste изглежда работи с много по-голям буфер:

$ coproc cat
$ echo 'Hello world!' >&${COPROC[1]}
$ read -ru ${COPROC[0]} line; echo $line
Hello world!
$ kill $COPROC_PID
[3]+  Terminated              coproc COPROC cat
$ 
$ coproc paste
[3] 42657
$ echo 'Hello world!' >&${COPROC[1]}
$ read -ru ${COPROC[0]} line; echo $line
#### read blocks here until ^C ####

Мисля, че причината за това е, че paste настройва своя режим на буфериране, в зависимост от това с какво е свързан, докато cat винаги е в режим на буфериране на линия.

Има ли някакъв начин да принудите paste (или друга обща команда) да бъде буферирана в ред в coproc?


След още малко експерименти открих, че мога да пресъздам подобно поведение без coprocs и вместо това просто прехвърляне между cat и paste:

$ cat | cat
Hello World!<RETURN>
Hello World!^D
$ cat | paste
Hello World!<RETURN>
Hello World!^D
$ paste | cat
Hello World!<RETURN>
#### command blocks here until ^C ####

(RETURN и ^D добавени за илюстрация)

  • Първо превеждаме cat до cat и получаваме буфериране на линията докрай
  • След това пренасяме cat до paste и също така получаваме буфериране на линията докрай
  • Накрая предаваме paste към cat и не получаваме буфериране на линията

Това изглежда показва, че paste ще буферира своя stdout, когато е в интерактивен режим, но в противен случай ще използва много по-голям буфер.


person Digital Trauma    schedule 07.01.2014    source източник


Отговори (1)


Един от начините за принудително буфериране на линии е да използвате инструмента stdbuf coreutils, ако е наличен:

stdbuf позволява да се променят операциите за буфериране от трите стандартни I/O потока, свързани с програма.

За случая coproc:

$ coproc stdbuf -oL paste
[3] 42751
$ echo 'Hello world!' >&${COPROC[1]}
$ read -ru ${COPROC[0]} line; echo $line
Hello world!
$ kill $COPROC_PID
[3]+  Terminated              coproc COPROC stdbuf -oL paste
$ 

За проста тръба от paste до cat случай:

$ stdbuf -oL paste | cat
Hello World!<RETURN>
Hello World!^D
$ 
person Digital Trauma    schedule 07.01.2014