Когда вы делаете:
cat fifo
Предполагая, что ни один другой процесс еще не открыл fifo
для записи, cat
заблокирует системный вызов open()
. Когда другой процесс открывает файл для записи, создается экземпляр канала и возвращается open()
. cat
будет вызывать read()
в цикле, а read()
будет блокироваться до тех пор, пока какой-либо другой процесс не запишет данные в конвейер.
cat
увидит конец -файла -(eof ), когда все остальные процессы записи закроют свой файловый дескриптор для fifo
. В каких точках cat
заканчивается и труба разрушается¹.
Вам нужно снова запустить cat
, чтобы прочитать то, что будет записано после этого в fifo
(, но через другой экземпляр канала ).
В:
tail -f file
Как и cat
, tail
будет ждать, пока процесс откроет файл для записи. Но здесь, поскольку вы не указали -n +1
для копирования с самого начала, tail
нужно будет дождаться eof, чтобы узнать, какими были последние 10 строк, поэтому вы ничего не увидите, пока не закончится запись. закрыто.
После этого tail
не будет закрывать свой fd для канала, что означает, что экземпляр канала не будет уничтожен, и по-прежнему будет пытаться читать из канала каждую секунду (в Linux, этого опроса можно избежать. с помощью inotify
и некоторые версии GNU tail
делают это там ). Это read()
сразу вернется с eof (, поэтому вы видите 100% CPU с -s 0
(, что с GNU tail
означает не ждать между read()
с вместо ожидания одной секунды ))пока какой-либо другой процесс снова не откроет файл для записи.
Вместо этого здесьвы можете использовать cat
, но убедитесь, что экземпляр канала всегда остается после того, как он был создан. Для этого в большинстве систем можно сделать:
cat 0<> fifo # the 0 is needed for recent versions of ksh93 where the
# default fd changed from 0 to 1 for the <> operator
cat
stdin будет открыт как для чтения, так и для записи, что означает, что cat
никогда не увидит на нем eof (он также сразу создает экземпляр канала, даже если нет другого процесса, открывающего fifo
для записи ).
В системах, где это не работает, вместо этого можно использовать:
cat < fifo 3> fifo
Таким образом, как только какой-либо другой процесс откроет fifo
для записи, будет возвращено первое чтение -только open()
, после чего оболочка выполнит запись -только open()
до запуск cat
, что предотвратит повторное разрушение трубы.
Итак, подводя итог:
cat file
, она не останавливалась после первого раунда. tail -n +1 -f file
:это не будет делать бесполезный read()
каждую секунду после первого раунда, никогда не будет eof на одном экземпляре канала, не будет задержки до одной секунды, когда второй процесс открывает канал для записи после того, как первый его закрыл. tail -f file
. В дополнение к вышесказанному, ему не нужно было бы ждать окончания первого раунда, прежде чем что-то выводить (только последние 10 строк ). cat file
в цикле будет только один экземпляр канала. Окон гонки, упомянутых в ¹, следует избегать. ¹ в этот момент между последним read()
, указывающим eof, и cat
, завершающим и закрывающим конец канала для чтения, на самом деле есть небольшие окна, в течение которых процесс может открыть fifo
для записи снова (и не быть заблокированным, так как все еще есть конец чтения ). Затем, если он что-то записывает после завершения cat
и до того, как другой процесс откроет fifo
для чтения, он будет уничтожен с помощью SIGPIPE.
Только с учетом этой информации единственным способом добиться желаемого будет использование правила iptables, которое будет перенаправлять все MAC-адреса, отличные от ваших, на нужный порт. Например что-то вроде этого:
iptables -t nat -A PREROUTING -p tcp --dport 22 -m mac ! --mac-source 11:22:33:44:55:66 -j DNAT --to 123.12.12.123:5006