У меня есть программа, которая производит полезную информацию, stdout
но также читает из stdin
. Я хочу перенаправить его стандартный вывод в файл, не предоставляя ничего для стандартного ввода. Пока все хорошо, я могу сделать:
program > output
и не делай ничего в tty.
Однако проблема в том, что я хочу сделать это в фоновом режиме. Если я сделаю:
program > output &
программа будет приостановлена («приостановлено (tty input)»).
Если я сделаю:
program < /dev/null > output &
программа немедленно завершается, потому что она достигает EOF.
Кажется, что мне нужно подключиться к program
чему-то, что ничего не делает в течение неопределенного времени и не читает stdin
. Работают следующие подходы:
while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &
Однако все это очень некрасиво. Там есть быть элегантным способом, с помощью стандартного утилита Unix, не «ничего не делать, до бесконечности» (перефразируя man true
). Как я мог этого добиться? (Мои главные критерии элегантности здесь: никаких временных файлов; никаких занятых или периодических пробуждений; никаких экзотических утилит; как можно короче.)
su -c 'program | output &' user
. Я собираюсь задать аналогичный вопрос с созданием фоновых заданий в качестве приемлемого метода для обработки «service / daemon». Я также заметил, что я не мог перенаправитьSTDERR
без перенаправленияSTDOUT
. Решение, в котором программа A отправляетSTDOUT
вSTDIN
программу B, а затем перенаправляетSTDERR
в файл журнала:programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/null
su -c 'while true; do true; done | cat > ~/output &' user
?1<&-
ним, выйдет из вашей программы?Ответы:
В оболочках, которые их поддерживают (ksh, zsh, bash4), вы можете начать
program
как совместный процесс .ksh
:program > output |&
zsh
,bash
:coproc program > output
Это начинается
program
в фоновом режиме с ввода, перенаправленного изpipe
. Другой конец трубы открыт для оболочки.Три преимущества такого подхода
program
умрете (используйте,wait
чтобы ждать его)program
завершится (войдитеeof
в свой стандартный ввод, если оболочка выйдет).источник
tail -f /dev/null
не идеален, так как выполняет чтение каждую секунду/dev/null
(в текущих версиях GNU tail для Linux, использующих inotify, на самом деле есть ошибка ).sleep inf
или его более переносимый эквивалентsleep 2147483647
- лучшие подходы для команды, которая сидит там и ничего не делает IMO (обратите внимание, чтоsleep
она встроена в несколько оболочек типаksh93
ormksh
).Я не думаю, что ты станешь более элегантным, чем
что вы уже предложили (при условии, что для внутреннего использования используется inotify, опросов или пробуждений не должно быть, поэтому, кроме странного вида, этого должно быть достаточно).
Вам нужна утилита, которая будет работать неопределенно долго, будет держать свой стандартный вывод открытым, но на самом деле ничего не будет записывать в стандартный вывод и не будет завершать работу, когда ее стандартный вывод закрыт. Нечто подобное на
yes
самом деле пишет в стандартный вывод.cat
выйдет, когда его стандартный ввод будет закрыт (или все, что вы перенаправили в него, будет сделано). Я думаю, чтоsleep 1000000000d
может работать, ноtail
явно лучше. В моей коробке Debian естьtailf
команда, которая немного укорачивает команду.Взять другой курс, как насчет запуска программы под
screen
?источник
tail -f /dev/null
подход лучше всего, и я нахожу его достаточно элегантным, поскольку использование команды довольно точно соответствует назначению.strace tail -f /dev/null
того, что кажется, чтоtail
используетinotify
и что пробуждения происходят в глупых случаях, какsudo touch /dev/null
. Грустно, что, кажется, нет лучшего решения ... Интересно, какой правильный системный вызов использовать для реализации лучшего решения.pause
, но он не напрямую подключен к интерфейсу оболочки.screen
, но это для запуска нескольких вхождений программы из сценария оболочки в целях тестирования, поэтому использоватьscreen
это немного излишне.sleep infinity
это самое ясное решение, которое я знаю.Вы можете использовать,
infinity
потому чтоsleep
принимает число с плавающей запятой * , которое может быть десятичным , шестнадцатеричным , бесконечностью или NaN , в соответствии сman strtod
.* Это не является частью стандарта POSIX, поэтому не так переносимо, как
tail -f /dev/null
. Однако он поддерживается в GNU coreutils (Linux) и BSD (используется на Mac) (очевидно, не поддерживается в более новых версиях Mac - см. Комментарии).источник
sleep infinity
также работает на BSD и Mac .sleep infinity
ждет в течение 24 дней максимум; кто прав?sleep
Утилита не ограничивается до 24 дней ; это всего лишь первый системный вызов, который спит в течение 24 дней, и после этого он будет делать больше таких системных вызовов. Смотрите мой комментарий здесь: stackoverflow.com/questions/2935183/…Да,
2^31-1
это конечное число, и оно не будет работать вечно , но я дам вам 1000 долларов, когда время сна наконец истечет. (Подсказка: один из нас к тому времени умрет.)источник
sleep 2147483647d
...Вы можете создать двоичный файл, который делает это с:
источник
Вот еще одно предложение использовать стандартные утилиты Unix, чтобы «ничего не делать, бесконечно» .
Это запускает оболочку, которая немедленно отправляется
SIGSTOP
, что приостанавливает процесс. Это используется как «вход» в вашу программу. ДополнениемSIGSTOP
являетсяSIGCONT
, т.е. если вы знаете, что оболочка имеет PID 12345, вы можетеkill -CONT 12345
сделать так, чтобы она продолжалась.источник
В Linux вы можете сделать:
В Linux, открыв / dev / fd / x, где x - дескриптор файла для конца записи канала, вы получите конец чтения канала, так что здесь то же самое, что и в stdin программы. Так что, по сути,
read
никогда не вернется, потому что единственное, что может записать в этот канал, это само по себе, иread
ничего не выводит.Он также будет работать на FreeBSD или Solaris, но по другой причине. Там, открыв / dev / fd / 1, вы получите тот же ресурс, что и open на fd 1, как и следовало ожидать, и как и большинство систем, кроме Linux, так что конец написания канала. Однако в FreeBSD и Solaris каналы являются двунаправленными. Поэтому до тех пор, пока
program
он не пишет в свой стандартный ввод (ни одно приложение не делает этого), онread
не получит ничего, чтобы читать с этого направления канала.В системах, где каналы не являются двунаправленными,
read
вероятно , произойдет сбой с ошибкой при попытке чтения из дескриптора файла только для записи. Также обратите внимание, что не все системы имеют/dev/fd/x
.источник
x
с Bash; далее с Zsh вы можете просто сделать,read
и это работает (хотя я не понимаю, почему!). Это трюк, специфичный для Linux, или он работает на всех * nix системах?read
один, он будет читать со стандартного ввода. Так что, если это терминал, он будет читать то, что вы вводите, пока вы не нажмете ввод.read
и это работает ?read | program > output
и это работает так же, как вы предложили. (И я не понимаю, почему.)read
Решение Стефана Чазела работает и на Mac OS X, если открыто чтение с fd/dev/fd/1
.Чтобы иметь возможность убивать
tail -f /dev/null
в скрипте (например, с помощью SIGINT), необходимо выполнитьtail
команду background иwait
.источник
Перенаправить
/dev/zero
как стандартный ввод!источник