Забороніть автоматичні EOF у названій трубі та надсилайте EOF, коли я цього хочу


12

У мене є програма, яка автоматично закривається після зчитування EOF у заданому потоці (у наступному випадку, stdin).
Тепер я хочу зробити скрипт оболонки, який створює іменовану трубку і підключає stdin програми до неї. Потім сценарій записує в трубу кілька разів, використовуючи echoі cat(та інші інструменти, які автоматично генерують EOF при виході). Проблема, з якою я стикаюся, полягає в тому, що коли echoце зроблено першим , він надсилає EOF в трубу і робить програму вихід. Якщо я використовую щось подібне, tail -fя не можу надсилати EOF, коли я маю намір вийти з програми. Я досліджую збалансоване рішення, але безрезультатно.
Я вже знайшов як запобігти EOF, так і як вручну відправити EOF, але не можу їх поєднувати. Чи є якийсь натяк?

#!/bin/sh
mkfifo P
program < P & : # Run in background
# < P tail -n +1 -f | program
echo some stuff > P # Prevent EOF?
cat more_stuff.txt > P # Prevent EOF?
send_eof > P # How can I do this?
# fg

Відповіді:


13

Як вказували інші, читач ефіру отримує EOF, коли не залишиться авторів. Таким чином, рішення полягає в тому, щоб переконатися, що завжди один автор письменника тримає його відкритим. Цей автор не повинен нічого надсилати, просто тримайте його відкритим.

Оскільки ви використовуєте скрипт оболонки, найпростіше рішення - сказати оболонці відкрити трубу для запису. А потім закрийте його, коли закінчите.

#!/bin/sh
mkfifo P
exec 3>P # open file descriptor 3 writing to the pipe
program < P
# < P tail -n +1 -f | program
echo some stuff > P
cat more_stuff.txt > P
exec 3>&- # close file descriptor 3

Зауважте, що якщо ви опустите останній рядок, дескриптор файлу 3 автоматично закриється (і, таким чином, читач отримає EOF), коли сценарій завершиться. Окрім зручності, це також забезпечує безпеку свого роду, якби сценарій якось достроково припинився.


2
ця exec 3>Pпричина зависає в баш, чому?
Ван

@Wang Це не повинно. Якщо це так, ви, ймовірно, не робите те саме, що і код POC у питанні. Єдина причина, по якій я можу подумати, що це блокується, це якщо ви замість цього робите щось на кшталт exec 2>P, і у вас увімкнено режим слідування ( set -x), в якому bash збирається записати в трубу, але читача немає, тому він блокує очікування щось читати.
Патрік

1
@Wang @Patrick Дійсно exec 3>Pвисить і на моїй машині. Це тому, що з нього не відбувається читання процесу P. Таким чином, рішенням було підміняти лінії exec 3>Pта program < P &(додавати амперсанд так, щоб програма працювала у фоновому режимі).
macieksk

2

Труба отримує EOF, коли останній письменник відходить. Щоб уникнути цього, переконайтесь, що завжди є автор (процес, у якому відкрита труба для написання, але насправді нічого не пише). Щоб надіслати EOF, змусьте цього резервного письменника піти.

mkfifo P
while sleep 1; do :; done >P &
P_writer_pid=$!
send_eof_to_P () {
  kill $P_writer_pid
}

0

Програма не може розрізнити EOF, що означає, що "час кинути", і EOF, що означає, що "письменник зроблений, але може бути більше інформації від когось іншого".

Якщо у вас є можливість змінювати поведінку вашої програми, виконайте читання в нескінченному циклі (одна ітерація триває до EOF) і надішліть їй певний командний рядок, що означає "час вийти". Надіслати цей рядок було б завданням send_eofкоманди у вашому запитанні.

Ще один варіант:

( echo some stuff; cat more_stuff.txt ) >P

або

{ echo some stuff; cat more_stuff.txt; } >P
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.