LINUX.ORG.RU

block => line buffering


0

0

Проблема:

Различные гнушные утилиты типа sed почему-то начинают blockwise буферизацию, если хотя бы один конец (stdin или stdout) сидит не на tty (а на пайпе или файле) (кстати, cat ведет себя не так). Видимо, дело в stdio -- она по умолчанию буферизует линейно, если дескриптор стрима это tty, и блочно в противном случае.

Вопрос:

Нельзя ли это как-нибудь изменить из оболочки (ну, там, переменную какую экспортировать)? Мне надо, чтобы sed (и tr), читающий/пишущий через пайп, буферизовал линейно.

★★★★★

> Различные гнушные утилиты типа sed почему-то начинают blockwise
> буферизацию, если хотя бы один конец (stdin или stdout) сидит не на
> tty (а на пайпе или файле) (кстати, cat ведет себя не так). Видимо,
> дело в stdio -- она по умолчанию буферизует линейно, если дескриптор
> стрима это tty, и блочно в противном случае.

Тут ты совершенно прав, только это все происходит не "почему-то", а
согласно докам (info libc это именно так все и описывает, и SUS
примерно так же).

> Нельзя ли это как-нибудь изменить из оболочки ...

Увы, никогда не слыхал о такой фиче :-(

Onanim
()
Ответ на: комментарий от Onanim

> только это все происходит не "почему-то", а согласно докам

Я не совсем понимаю, почему, когда я сажаю stdin (_не_ stdout, а именно stdin) на пайп, то sed вдруг начинает блочную буферизацию:

cat |sed 's/a/b/g'

> Увы, никогда не слыхал о такой фиче :-(

Я тоже :(

Но, может, есть?

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Die-Hard

можно 
1) попробовать посылать sed`у сигналы..
какой-нить SIGTTOU SIGTTIN 
2) установить TERM=dumb до вызова sed
3) вместо cat использовать свой pager который на каждую строку 
принудительно делает fflush (fsync/fdatasync)
4) запускать sed с опцией -u 

где-то так...

MKuznetsov ★★★★★
()
Ответ на: комментарий от Die-Hard

> Я не совсем понимаю, почему, когда я сажаю stdin (_не_ stdout, а
> именно stdin) на пайп, то sed вдруг начинает блочную буферизацию:
>
> cat |sed 's/a/b/g'
>

Дык sed тут причем?
Это (теоретически) cat должен буферизировать свой stdout
потому, что он не interactive device (не tty), а пайп.
Я написал "теретически" потому, что cat вроде отключает буферизацию,
по крайней мере у меня:

$ cat |sed 's/a/b/g'
axyz # мой input
bxyz
aaa # мой input
bbb
^D
$

Так что лучше для иллюстрации принципов cat не использовать :-)))

Смотри, возьмем для примера pipeline из компонент, в которых мы
заведомо контролируем буферизацию:

perl -pe 42 | perl -pe '$|++'

Первый perl работает как cat (тока с буферизацией по default),
а второй perl - как cat без всякой буферизации:

$ perl -pe 42 | perl -pe '$|++'
My input line 1
My input line 2
Some more input
^D
My input line 1
My input line 2
Some more input
$

Видишь, то есть это _первый_ perl буферизовал свой stdout и не давал
данных второму (и сбросил буфер тока при EOF).
Мы это знаем точно - потому, что второй perl был бы и рад напечатать
данные немедленно, да никто ему их не давал.

Такая вот фигня. AFAIK остальные традиционные unix-фильтры типа
sed, grep, awk... ведут себя именно "по умолчанию" а не так, как cat.

HTH

Onanim
()
Ответ на: комментарий от Onanim

2Onanim:

Ты вопроса не понял...

> Так что лучше для иллюстрации принципов cat не использовать :-)))

Я потому и использовал cat, что он не буферизует.

Вопрос же такой:

Какого лешего sed буферизует _output_, который на tty, когда его _input_ приаттачен к пайпу? Пример:

cat | sed ....

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от MKuznetsov

2MKuznetsov:

Thanks,

> 4) запускать sed с опцией -u

То, что надо!

Остальное -- мимо:

> 1) попробовать посылать sed`у сигналы.. какой-нить SIGTTOU SIGTTIN

Не помогает. Он переходит в "T" потом я его бужу, но он буфер не выталкивает.

> 2) установить TERM=dumb до вызова sed

Не помогает.

> 3) вместо cat использовать свой pager который на каждую строку принудительно делает fflush (fsync/fdatasync)

не подходит: мне нужна именно системная стандартная утилита: это мне надо для иллюстрации, чтобы было всем понятно без дополнительных комментариев.

Теперь бы еще про tr такое же найти.

Кстати, tr ведет себя более понятно:

cat| tr a b

буферизует линейно.

Мне же хочется, чтобы работало такое:

cat | tr a b | cat

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Die-Hard

> Ты вопроса не понял...
> Какого лешего sed буферизует _output_, который на tty, когда его
> _input_ приаттачен к пайпу? Пример:

Хмм... я потому и не понял, что у меня все нормально:

$ cat |sed 's/a/b/g'
axyz # мой input
bxyz # output от sed
aaa # мой input
bbb # output от sed
^D
$

Ничего sed не буферизирует... было бы странно такое от него ожидать...
на трех машинах проверил :-/

Onanim
()
Ответ на: комментарий от Onanim

2Onanim:

> Ничего sed не буферизирует... было бы странно такое от него ожидать... 
на трех машинах проверил :-/

Вот тебе и раз...
Дык это просто баг оказывается!

У меня:

$cat|sed 's/a/b/g'
aaaa
aaaa
aaaa
aaaa
^D
bbbb
bbbb
bbbb
bbbb

$sed -V
GNU sed version 3.02.80

Но на другой машине:

$cat|sed 's/a/b/g'
aaaaa
bbbbb
aaaaa
bbbbb
aaaaa
bbbbb
^D

$sed -V
GNU sed version 4.0.7

Ок, всем спасибо.

Может, кто еще что про tr подскажет :-)?

Die-Hard ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.