У меня нет большого опыта использования тройника, поэтому я надеюсь, что это не очень просто.
После просмотра одного из ответов на этот вопрос я столкнулся со странным поведением tee
.
Чтобы вывести первую строку и найденную строку, я могу использовать это:
ps aux | tee >(head -n1) | grep syslog
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
syslog 806 0.0 0.0 34600 824 ? Sl Sep07 0:00 rsyslogd -c4
Однако, когда я впервые запустил этот (в zsh) результат был в неправильном порядке, заголовки столбцов были ниже результатов grep (однако это не повторилось), поэтому я попытался поменять местами команды:
ps aux | tee >(grep syslog) | head -n1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
Печатается только первая строка, и больше ничего! Могу ли я использовать tee для перенаправления на grep, или я делаю это неправильно?
Когда я набирал этот вопрос, вторая команда фактически сработала один раз для меня, я запустил ее снова пять раз, а затем вернулся к результату в одну строку. Это только моя система? (Я запускаю Zsh в Tmux).
И наконец, почему с первой командой «grep syslog» не отображается как результат (результат только один)?
Для контроля здесь grep без tee
ps aux | grep syslog
syslog 806 0.0 0.0 34600 824 ? Sl Sep07 0:00 rsyslogd -c4
henry 2290 0.0 0.1 95220 3092 ? Ssl Sep07 3:12 /usr/bin/pulseaudio --start --log-target=syslog
henry 15924 0.0 0.0 3128 824 pts/4 S+ 13:44 0:00 grep syslog
Обновление: кажется, что head заставляет целую команду обрезаться (как указано в ответе ниже), теперь приведенная ниже команда возвращает следующее:
ps aux | tee >(grep syslog) | head -n1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
syslog 806
ps aux | sed -n -e '1p' -e '/syslog/p'
.Ответы:
grep
Иhead
команды начинаются примерно в то же время, и оба получают одни и те же входные данные в их собственном досуге, но в целом, так как данные становятся доступными. Есть некоторые вещи, которые могут вводить «несинхронизированный» вывод, который переворачивает строки; например:Мультиплексированные данные
tee
фактически отправляются одному процессу раньше другого, в зависимости, в первую очередь, от реализацииtee
. Простаяtee
реализация потребуетread
некоторого количества ввода, а затемwrite
дважды: один раз в стандартный вывод и один раз в аргумент. Это означает, что один из этих пунктов назначения получит данные в первую очередь.Однако трубы все забуферены. Вполне вероятно, что эти буферы занимают 1 строку каждый, но они могут быть больше, что может привести к тому, что одна из принимающих команд увидит все, что ей нужно для вывода (т.
grep
Е. Строку ped), до того, как другая команда (head
) получит какие-либо данные в все.Несмотря на вышесказанное, также возможно, что одна из этих команд получает данные, но не может ничего с ними сделать вовремя, а затем другая команда получает больше данных и быстро их обрабатывает.
Например, даже если
head
иgrep
отправляются данные по одной строке за раз, еслиhead
он не знает, как с этим справиться (или его задерживает планирование ядра), онgrep
может показать свои результатыhead
еще до того, как получит шанс. Чтобы продемонстрировать, попробуйте добавить задержку:ps aux | tee >(sleep 1; head -n1) | grep syslog
это почти наверняка выведет вывод вgrep
первую очередь.Я считаю, что вы часто получаете только одну строку, потому что
head
получает первую строку ввода, а затем закрывает свой стандартный ввод и завершает работу. Когдаtee
видит, что его стандартный вывод был закрыт, он закрывает собственный стандартный вывод (вывод изps
) и завершает работу. Это может зависеть от реализации.По сути, единственными данными, которые
ps
можно отправить, является первая строка (определенно, потому чтоhead
она контролирует это) и, возможно, некоторые другие строки передhead
&tee
закрытием их дескрипторов stdin.Несоответствие тому, появляется ли вторая строка, связано с синхронизацией:
head
закрывает стандартный ввод, ноps
все еще отправляет данные. Эти два события не очень хорошо синхронизированы, поэтому строка, содержащая их,syslog
все еще имеет шанс сделать ееtee
аргументом (grep
командой). Это похоже на объяснения выше.Вы можете полностью избежать этой проблемы, используя команды, которые ждут весь ввод перед закрытием stdin / exiting. Например, используйте
awk
вместоhead
, который будет читать и обрабатывать все его строки (даже если они не вызывают вывода):Но обратите внимание, что строки все еще могут появляться не в порядке, как указано выше, что можно продемонстрировать с помощью:
Надеюсь, что это не слишком много деталей, но есть много одновременных вещей, взаимодействующих друг с другом. Отдельные процессы выполняются одновременно без какой-либо синхронизации, поэтому их действия при каждом конкретном запуске могут отличаться; иногда это помогает углубиться в основные процессы, чтобы объяснить, почему.
источник
ps aux | tee >(grep syslog) | head -n1
который бы прекратилhead
закрывать стандартный вывод. Ух ты, эта команда начала выдавать вывод, но, как и в случае с твоим ответом, она выглядит усеченнойUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
syslog 806
head
. Я обновил ответ на этом примере:ps aux | tee >(grep syslog) | awk 'NR == 1'
>(cmd)
, оболочка создает именованный канал и передает его в качестве аргумента команде (tee
). Затемtee
пишет в стандартный вывод (по каналуawk
), а также в этот аргумент. Это так же, какmkfifo a_fifo ; grep ... a_fifo
в одной оболочке иps | tee a_fifo | awk ...
в другой.echo >(exit 0)
, который отзовется фактический аргумент , передаваемый оболочкой (в моем случае, это будет/dev/fd/63
). Это должно работать одинаково на bash и zsh.grep syslog
не всегда отображается, так как это зависит от времени. При использовании оболочки конвейера вы выполняете команды практически одновременно. Но ключевым здесь является слово «почти». Еслиps
сканирование всех процессов завершается до запуска grep, его нет в списке. Вы можете получить случайные результаты в зависимости от загрузки системы и т. Д.Похожая вещь случается с твоей футболкой. Он запускается в фоновом режиме в подоболочке и может запускаться до или после grep. Вот почему порядок вывода не согласован.
Что касается вопроса, это поведение довольно странно. Это потому, что он не используется в обычном режиме. Он запускается без каких-либо аргументов, что означает, что он должен просто копировать данные из своего стандартного ввода в стандартный вывод. Но его стандартный вывод перенаправляется на запущенную головку subshell (в первом случае) или grep (во втором случае). Но это также передается следующей команде. Я думаю, что то, что происходит в этом случае, на самом деле зависит от реализации. Например, на моем bash 4.2.28 ничего не пишется в subshell stdin. На zsh он работает надежно так, как вы хотели бы (печатая как первую строку ps, так и искомые строки), каждый раз, когда я пытаюсь,
источник
Немного хакерски, но вот мое решение в виде
psgrep()
функции оболочки, которую я использую:Перенаправьте
ps
строку заголовкаSTDERR
, затемgrep
включитеSTDOUT
, но сначала удалитеgrep
саму команду, чтобы избежать появления строки «noise»grep
:источник