Как обработать именованный канал без ожидания

Возможно, это относится к категории "обходной путь", но мне удалось достичь того, что я думаю, ваша цель - ввести команду ("python dostuff.py "из вашего примера) в сценарий оболочки, затем запустив ... screen -d -m" / path / to / that / script "

Информация о версии:

$ screen -v
Screen version 3.09.10 (FAU) 4-Sep-01

Похоже, у меня довольно старая версия экрана в этой системе! Возможно, поведение экрана изменилось в более поздних версиях для автоматического выхода?

$ screen -ls
No Sockets found in /tmp/uscreens/S-username.
$ screen -dm "ls"
$ screen -ls
There is a screen on:
        32112694.ls     (Detached)
1 Socket in /tmp/uscreens/S-username.

(screen -r; exit)

$ screen -ls
No Sockets found in /tmp/uscreens/S-username.

$ cat runme
#!/bin/sh
sleep 6
ls > now

$ screen -d -m ./runme
$ ps -ef|grep sleep
 username 9633926  9437204   0 14:55:23  pts/1  0:00 grep sleep
 username 15532242 10223670   0 14:55:21  pts/6  0:00 sleep 6

(подождите 6 секунд)

$ screen -ls
No Sockets found in /tmp/uscreens/S-username.
$ ls now
now

Одна вещь, которую я понял, проходя через это, заключается в том, что моя версия screen, похоже, ожидала имя сеанса после -dm ; Мне пришлось разделить -d и -m , чтобы передать аргумент команды.

Попробуйте использовать:

ssh user@host screen -d -m python dostuff.py

с необязательным -S , чтобы присвоить сеансу какое-то конкретное имя.

2
04.06.2019, 20:32
2 ответа

Чтобы catне зависал при отсутствии какой-либо записи, (в этом случае зависает именно открытие fifo, а не чтение из него ), можно сделать:

cat 0<> "$my_named_pipe" <"$my_named_pipe"

Первое перенаправление открывается в режиме чтения+записи, который в большинстве систем не блокирует и создает экземпляр канала, даже если ни писатель, ни читатель уже отсутствуют. Затем второе открытое (чтение -только на этот раз )не будет блокироваться, потому что теперь есть по крайней мере один писатель (сам ).

0требуется только в последних версиях ksh93, где значение fd по умолчанию для <>изменено с 0 на 1.

Кроме того, в ksh93это не будет работать, когда catявляется встроенной оболочкой, например, когда ksh93вызывается, когда /opt/ast/binопережает /binв $PATHили после вызова builtin cat, как и <"$my_named_pipe", (, я думаю, )ksh93 сохраняет предыдущую цель стандартного ввода в отдельном дескрипторе файла, который будет держать канал открытым.Вы можете обойти это, написав вместо этого:

cat 3<> "$my_named_pipe" <"$my_named_pipe" 3<&-

(что, как вы могли бы также утверждать, более четко передает намерение)

Обратите внимание, что <>в канале также разблокирует другие считыватели для доступа к fifo.

Если бы были некоторые писатели, catвсе равно пришлось бы читать весь их вывод и ждать, пока они не закроют свой конец канала. Вы можете открыть канал в неблокирующем режиме -, например, в GNU dd:

.
dd bs=64k if="$my_named_pipe" iflag=nonblock status=noxfer

Который будет читать из канала только до тех пор, пока в нем есть какие-то данные, и выходить с

dd: error reading 'fifo': Resource temporarily unavailable

ошибка, когда больше нет, и не разблокировать других читателей, но это означает, что вы можете пропустить вывод некоторых модулей записи, если они медленнее записывают в канал, чем вы(dd)читаете его.

Другим подходом может быть тайм-аут, когда в течение некоторого времени не было ввода, например, с помощью socatопции -T:

socat -u -T1 - - 0<> "$my_named_pipe" <"$my_named_pipe"

Который вышел бы, если бы из трубы ничего не исходило в течение одной секунды.

8
27.01.2020, 21:58

Что-то довольно простое — завершить catсразу после чтения fifo, независимо от того, есть данные или нет. Вы можете сделать это с помощью timeoutследующим образом:

timeout 2 cat my_named_pipe

Выше timeoutждет две секунды, прежде чем принудительно завершить работу cat. Если при запуске catв именованном канале есть что-то буферизованное, оно будет выведено на стандартный вывод.

Возможно, это не самое чистое решение, но оно работает.

Надеюсь, это поможет.

1
27.01.2020, 21:58

Теги

Похожие вопросы