Вы могли использовать комбинацию GNU stdbuf и pee
от moreutils:
echo "Hello world!" | stdbuf -o 1M pee cmd1 cmd2 cmd3 > output
моча popen(3)
s те 3 командных строки оболочки и затем fread
s вход и fwrite
s все это три, который будет буферизован к до 1M.
Идея состоит в том, чтобы иметь буфер, по крайней мере, столь же большой как вход. Этот путь даже при том, что три команды запускаются одновременно, они будут только видеть, что вход входит когда pee
pclose
s три команды последовательно.
На каждого pclose
, pee
сбрасывает буфер к команде и ожидает ее завершения. Это гарантирует что настолько же долго как они cmdx
команды не начинают производить что-либо, прежде чем они получили любой вход (и не разветвляйте процесс, который может продолжить производить после того, как их родитель возвратился), вывод трех команд не будет чередован.
В действительности это немного похоже на использование временного файла в памяти с недостатком, что 3 команды запускаются одновременно.
Чтобы постараться не запускать команды одновременно, Вы могли записать pee
как функция оболочки:
pee() (
input=$(cat; echo .)
for i do
printf %s "${input%.}" | eval "$i"
done
)
echo "Hello world!" | pee cmd1 cmd2 cmd3 > out
Но остерегайтесь, который окружает кроме zsh
перестал бы работать для двоичного входа с символами NUL.
Это избегает использования временных файлов, но это означает, что целый вход хранится в памяти.
В любом случае необходимо будет сохранить вход где-нибудь в памяти или временном файле.
На самом деле это - вполне интересный вопрос, поскольку это показывает нам, предел идеи Unix наличия нескольких простых инструментов сотрудничает к единственной задаче.
Здесь, мы хотели бы иметь несколько инструментов, сотрудничают к задаче:
echo
)tee
)cmd1
, cmd2
, cmd3
)cat
).Было бы хорошо, если они могли бы все работать вместе одновременно и сделать свою тяжелую работу на данных, которые они предназначены для обработки, как только это доступно.
В случае одной команды фильтрации это легко:
src | tee | cmd1 | cat
Все команды выполняются одновременно, cmd1
начинает громко жевать данные из src
как только это доступно.
Теперь, с тремя командами фильтрации, мы можем все еще сделать то же: запустите их одновременно и соедините их с каналами:
┏━━━┓▁▁▁▁▁▁▁▁▁▁┏━━━━┓▁▁▁▁▁▁▁▁▁▁┏━━━┓
┃ ┃░░░░2░░░░░┃cmd1┃░░░░░5░░░░┃ ┃
┃ ┃▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┃ ┃
┏━━━┓▁▁▁▁▁▁▁▁▁▁┃ ┃▁▁▁▁▁▁▁▁▁▁┏━━━━┓▁▁▁▁▁▁▁▁▁▁┃ ┃▁▁▁▁▁▁▁▁▁┏━━━┓
┃src┃░░░░1░░░░░┃tee┃░░░░3░░░░░┃cmd2┃░░░░░6░░░░┃cat┃░░░░░░░░░┃out┃
┗━━━┛▔▔▔▔▔▔▔▔▔▔┃ ┃▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┃ ┃▔▔▔▔▔▔▔▔▔┗━━━┛
┃ ┃▁▁▁▁▁▁▁▁▁▁┏━━━━┓▁▁▁▁▁▁▁▁▁▁┃ ┃
┃ ┃░░░░4░░░░░┃cmd3┃░░░░░7░░░░┃ ┃
┗━━━┛▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┗━━━┛
Который мы можем сделать относительно легко с именованными каналами:
pee() (
mkfifo tee-cmd1 tee-cmd2 tee-cmd3 cmd1-cat cmd2-cat cmd3-cat
{ tee tee-cmd1 tee-cmd2 tee-cmd3 > /dev/null <&3 3<&- & } 3<&0
eval "$1 < tee-cmd1 1<> cmd1-cat &"
eval "$2 < tee-cmd2 1<> cmd2-cat &"
eval "$3 < tee-cmd3 1<> cmd3-cat &"
exec cat cmd1-cat cmd2-cat cmd3-cat
)
echo abc | pee 'tr a A' 'tr b B' 'tr c C'
(выше } 3<&0
должен работать вокруг факта это &
перенаправления stdin
от /dev/null
, и мы используем <>
избегать открытия каналов для блокирования до другого конца (cat
) открылся также),
Или избегать именованных каналов, немного более мучительно с zsh
coproc:
pee() (
n=0 ci= co= is=() os=()
for cmd do
eval "coproc $cmd $ci $co"
exec {i}<&p {o}>&p
is+=($i) os+=($o)
eval i$n=$i o$n=$o
ci+=" {i$n}<&-" co+=" {o$n}>&-"
((n++))
done
coproc :
read -p
eval tee /dev/fd/$^os $ci "> /dev/null &" exec cat /dev/fd/$^is $co
)
echo abc | pee 'tr a A' 'tr b B' 'tr c C'
Теперь, вопрос: после того как все программы запущены и соединены, будет поток данных?
У нас есть два ограничения:
tee
подача все его выводы на том же уровне, таким образом, это может только диспетчеризировать данные по курсу своего самого медленного выходного канала.cat
только начнет читать из второго канала (передайте по каналу 6 в рисунке выше), когда все данные были считаны с первого (5).То, что это означает, - то, что данные не будут течь в канале 6 до cmd1
закончился. И, как в случае tr b B
выше, который может означать, что данные не будут течь в канале 3 или, что означает, это не будет течь ни в одном из каналов 2, 3 или 4 с тех пор tee
подача на самом медленном уровне всех 3.
На практике те каналы имеют непустой размер, таким образом, некоторым данным удастся пройти, и в моей системе, по крайней мере, я могу заставить это работать до:
yes abc | head -c $((2 * 65536 + 8192)) | pee 'tr a A' 'tr b B' 'tr c C' | uniq -c -c
Кроме того, с
yes abc | head -c $((2 * 65536 + 8192 + 1)) | pee 'tr a A' 'tr b B' 'tr c C' | uniq -c
У нас есть мертвая блокировка, где мы находимся в этой ситуации:
┏━━━┓▁▁▁▁2▁▁▁▁▁┏━━━━┓▁▁▁▁▁5▁▁▁▁┏━━━┓
┃ ┃░░░░░░░░░░┃cmd1┃░░░░░░░░░░┃ ┃
┃ ┃▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┃ ┃
┏━━━┓▁▁▁▁1▁▁▁▁▁┃ ┃▁▁▁▁3▁▁▁▁▁┏━━━━┓▁▁▁▁▁6▁▁▁▁┃ ┃▁▁▁▁▁▁▁▁▁┏━━━┓
┃src┃██████████┃tee┃██████████┃cmd2┃██████████┃cat┃░░░░░░░░░┃out┃
┗━━━┛▔▔▔▔▔▔▔▔▔▔┃ ┃▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┃ ┃▔▔▔▔▔▔▔▔▔┗━━━┛
┃ ┃▁▁▁▁4▁▁▁▁▁┏━━━━┓▁▁▁▁▁7▁▁▁▁┃ ┃
┃ ┃██████████┃cmd3┃██████████┃ ┃
┗━━━┛▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┗━━━┛
Мы заполнили каналы 3 и 6 (64 кибибита каждый). tee
считал, что дополнительный байт, это подало его к cmd1
, но
cmd2
освободить егоcmd2
не может освободить его, потому что это заблокировало запись на канале 6, ожидая cat
освободить егоcat
не может освободить его, потому что это ожидает, до там больше не вводится на канале 5.cmd1
не может сказать cat
там больше не вводится, потому что это ожидает само более входа от tee
.tee
не может сказать cmd1
там больше не вводится, потому что это заблокировалось... и так далее.У нас есть цикл зависимостей и таким образом мертвая блокировка.
Теперь, каково решение? Большие каналы 3 и 4 (достаточно большой для содержания всего из src
вывод), сделал бы это. Мы могли сделать это, например, путем вставки pv -qB 1G
между tee
и cmd2/3
где pv
мог сохранить до 1G данных, ожидающих cmd2
и cmd3
считать их. Это означало бы две вещи хотя:
cmd2
в действительности только начал бы обрабатывать данные, когда cmd1 закончился.Решение второй проблемы состояло бы в том, чтобы сделать каналы 6 и 7 больших также. Принятие этого cmd2
и cmd3
произведите так очень вывод, как они используют, который не использовал бы больше памяти.
Единственный способ постараться не копировать данные (в первой проблеме) состоял бы в том, чтобы реализовать хранение данных в диспетчере самих, который является реализацией вариация на tee
это может подать данные по курсу самого быстрого вывода (содержащий данные для питания более медленных в их собственном темпе). Едва ли тривиальный.
Так, в конце лучшее, которое мы можем обоснованно получить без программирования, является, вероятно, чем-то как (синтаксис Zsh):
max_hold=1G
pee() (
n=0 ci= co= is=() os=()
for cmd do
if ((n)); then
eval "coproc pv -qB $max_hold $ci $co | $cmd $ci $co | pv -qB $max_hold $ci $co"
else
eval "coproc $cmd $ci $co"
fi
exec {i}<&p {o}>&p
is+=($i) os+=($o)
eval i$n=$i o$n=$o
ci+=" {i$n}<&-" co+=" {o$n}>&-"
((n++))
done
coproc :
read -p
eval tee /dev/fd/$^os $ci "> /dev/null &" exec cat /dev/fd/$^is $co
)
yes abc | head -n 1000000 | pee 'tr a A' 'tr b B' 'tr c C' | uniq -c
ПРИМЕЧАНИЕ:[1186720] Первая часть команды, [1186721]netstat -anpt 2>&1 | tail -n +5 ...[1186722] направит всю выходную мощность, которая может произойти на STDOUT, также на STDIN, а затем отрежет первые 5 строк, которые являются выходной мощностью котла из [1186723]netstat[1186724], в которых мы не заинтересованы.
Пример
Вы можете использовать аналогичный подход для получения подсчетов, используя различные инструменты, такие как [1186725]wc[1186726] или [1186727]uniq -c[1186728].
Изменение вывода
Наконец, чтобы сделать то, что вы хотите с точки зрения подсчета вхождений:
Первый столбец представляет подсчет.[1186301]
из wikipedia
On Linux,
netstat
(часть "net-tools") является deprecated, вместо него следует использоватьss
(часть iproute2).
В пакете net-tools уже более десяти лет не выпускается Linux. Это долгое время без обновления программного пакета, предназначенного для управления и мониторинга постоянно изменяющихся коммуникационных интерфейсов ядра - особенно когда речь идёт о ядре, которое практически работает в интернете.
К счастью, существует активно поддерживаемый пакет iproute2, который включает в себя утилиту ss
.
С помощью ss
вы можете делать то, о чем просите, например:
ss -np state ESTABLISHED
из man ss
:
#USAGE EXAMPLES
ss -t -a
# Display all TCP sockets.
#
ss -t -a -Z
# Display all TCP sockets with process SELinux
# security contexts.
#
ss -u -a
# Display all UDP sockets.
#
ss -o state established '( dport = :ssh or sport = :ssh )'
# Display all established ssh connections.
#
ss -x src /tmp/.X11-unix/*
# Find all local processes connected to X server.
#
ss -o state fin-wait-1 '( sport = :http or sport = :https )' dst 193.233.7/24
# List all the tcp sockets in state FIN-WAIT-1
# for our apache to network 193.233.7/24 and
# look at their timers.
Я очень ценю такую помощь, поэтому пришло время сотрудничать:
netstat -tun | grep 1521 | awk '{print $6}' | uniq -c