Как использовать тройник для перенаправления на grep

У меня нет большого опыта использования тройника, поэтому я надеюсь, что это не очень просто.

Просмотрев один из ответов на этот вопрос, я наткнулся на странного beheviour с 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 

Печатается только первая строка, и больше ничего! Могу ли я использовать тройник для перенаправления на 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 

Обновление. Кажется, что голова вызывает усечение всей команды (как указано в ответе ниже), приведенная ниже команда возвращает следующее:

 ps aux | tee >(grep syslog) | head -n1 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND syslog 806 

  • Неудачное решение от «Как перенаправить stdout и stderr в файл и отобразить stderr для консоли»
  • как перенаправить вывод в несколько файлов журнала
  • Как работает `: w! Sudo tee%`
  • Как я могу удалить файл защиты, сделанный tee?
  • тире: Труба STDIN к нескольким командам и их вывод в STDOUT в определенном порядке
  • Как использовать тройник для захвата STDOUT из кодового блока в имя файла, определенное в блоке?
  • tee stdout to stderr?
  • значение переменной оболочки для цикла, отличного от цикла
  • 3 Solutions collect form web for “Как использовать тройник для перенаправления на grep”

     $ 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 

    Команды grep и head начинаются примерно в одно и то же время, и оба получают одни и те же входные данные на собственном отдыхе, но обычно, когда данные становятся доступными. Есть некоторые вещи, которые могут ввести «несинхронизированный» вывод, который переворачивает строки; например:

    1. Мультиплексированные данные из tee фактически отправляются в один процесс перед другим, в зависимости, в основном, от реализации tee . Простая реализация tee будет read некоторый объем ввода, а затем write его дважды: один раз в stdout и один раз до его аргумента. Это означает, что одно из этих мест назначения получит данные в первую очередь.

      Тем не менее, трубы все буферизованы. Вполне вероятно, что эти буферы по 1 строке, но они могут быть больше, что может привести к тому, что одна из принимающих команд увидит все, что ему нужно для вывода (т. grep Линии grep ped), прежде чем другая команда ( head ) получит любую данных вообще.

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

      Например, даже если head и grep отправляются данные по одной строке за раз, если head не знает, как с этим бороться (или откладывается при планировании ядра), grep может показать свои результаты, прежде чем head даже получит шанс , Чтобы продемонстрировать, попробуйте добавить задержку: ps aux | tee >(sleep 1; head -n1) | grep syslog ps aux | tee >(sleep 1; head -n1) | grep syslog ps aux | tee >(sleep 1; head -n1) | grep syslog Это почти наверняка выведет выход grep .

     $ ps aux | tee >(grep syslog) | head -n1 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND 

    Я считаю, что вы часто получаете только одну строку, потому что head получает первую строку ввода, а затем закрывает свой stdin и выходит. Когда tee видит, что его stdout был закрыт, он затем закрывает свой собственный stdin (вывод из ps ) и выходит. Это может быть зависящим от реализации.

    Фактически, единственные данные, которые ps получает для отправки, – это первая строка (определенно, потому что head контролирует это), и, возможно, некоторые другие строки перед тем, как head & tee закрывают дескрипторы stdin.

    Несогласованность появления второй строки вводится по времени: head закрывает stdin, но ps все еще отправляет данные. Эти два события не очень хорошо синхронизированы, поэтому строка, содержащая syslog все еще имеет шанс сделать ее аргументом tee (команда grep ). Это похоже на приведенные выше объяснения.

    Вы можете вообще избежать этой проблемы, используя команды, которые ждут ввода всех данных перед закрытием stdin / exiting. Например, используйте awk вместо head , который будет читать и обрабатывать все его строки (даже если они не вызывают выход):

     ps aux | tee >(grep syslog) | awk 'NR == 1' 

    Но обратите внимание, что линии могут по-прежнему отображаться вне порядка, как указано выше, что может быть продемонстрировано:

     ps aux | tee >(grep syslog) | (sleep 1; awk 'NR == 1') 

    Надеюсь, это было не слишком подробно, но есть много одновременных вещей, взаимодействующих друг с другом. Отдельные процессы запускаются одновременно без какой-либо синхронизации, поэтому их действия на любом конкретном прогоне могут варьироваться; иногда это помогает углубиться в основные процессы, чтобы объяснить, почему.

    grep syslog не всегда отображается, так как зависит от времени. При использовании оболочки оболочки вы выполняете команды почти одновременно. Но главное здесь слово «почти». Если ps завершает сканирование всех процессов до запуска grep, оно не будет в списке. Вы можете получить случайные результаты в зависимости от нагрузки системы и т. Д.

    Подобное происходит с вашим тройником. Он запускается на фоне в подоболочке и может быть запущен до или после grep. Поэтому порядок вывода несовместим.

    Что касается вопроса о типе, это поведение довольно странно. Это потому, что он не используется в обычном режиме. Он запускается без каких-либо аргументов, что означает, что он должен просто скопировать данные из его stdin в stdout. Но это stdout перенаправляется на головку подголовника (в первом случае) или grep (2-й случай). Но он также передается по следующей команде. Я думаю, что то, что происходит в этом случае, зависит от реализации. Например, в моем bash 4.2.28 ничего не записывается в subhell stdin. На zsh он работает надежно, как вам хотелось бы (печать как первой строки ps, так и строк поиска), каждый раз, когда я пытаюсь,

    Немного хакерский, но вот мое решение, в виде функции psgrep() я использую:

    Переадресовываем строку заголовка ps в STDERR , затем grep на STDOUT , но сначала удаляем команду grep , чтобы избежать строки «шум», вытекающей из самой grep :

     psgrep() { ps aux | tee >(head -1>&2) | grep -v " grep $@" | grep "$@" -i --color=auto; } 
    Linux и Unix - лучшая ОС в мире.