Некоторое время я использовал следующую команду, чтобы сохранить заголовки на выходе ps.
ps aux | { head -1; grep root; }
Результат будет выглядеть примерно так.
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
root 142 0.0 0.0 1234567 2520 ?? Ss 3:14AM 0:08.03 /usr/sbin/notifyd
root 55 0.0 0.0 7890123 2460 ?? Ss 3:14AM 0:01.94 /usr/sbin/syslogd
...
Однако при использовании с другими программами командной строки вывод не такой, как ожидалось.
Возьмем следующий пример df.
df -h
Выводит следующее.
Filesystem Size Used Avail Use% Mounted on
/dev/disk1s1 466G 103G 362G 22% /
/dev/disk1s4 466G 1.1G 362G 1% /blah/blah/blah
Использование df с синтаксисом, аналогичным приведенному выше примеру с ps.
df -h | { head -1; grep disk1; }
Выводит следующее.
Filesystem Size Used Avail Use% Mounted on
Ожидается, что вывод будет выглядеть практически так же, как прямая команда df -h.
Чем это отличается от ps?
Я чувствую, что знание этих различий поможет мне более полно понять обработку BASH.
Спасибо!
Stack Overflow - это сайт для вопросов по программированию и разработке. Этот вопрос кажется не по теме, потому что он не о программировании или разработке. См. О каких темах я могу спросить здесь в Справочном центре. Возможно, лучше спросить Суперпользователь или Обмен стеков Unix и Linux.





Это потому, что head буферизует свой ввод. Он считывает из конвейера большой буфер, а затем начинает извлекать строки из этого буфера. После того, как он прочитал и напечатал первые N строк, он закрывается. Затем grep начинает чтение с трубы. Но все, что head уже прочитало в свой буфер, недоступно.
Причина, по которой он, кажется, работает с ps, заключается в том, что он производит много вывода, который не помещается в этот буфер. Затем grep сможет обработать остальную часть вывода. Но я думаю, если вы внимательно посмотрите, то увидите, что результат неполный.
Вывод df намного меньше, он все умещается в буфере, который использует head, так что grep нечего обрабатывать.
Размер буфера, вероятно, составляет около 4К символов.
С awk вы можете делать все, что хотите:
df -h | awk 'NR == 1 || /disk1/'
ps aux | awk 'NR == 1 || /root/'
NR - это номер строки, поэтому он печатает строку, если это первая строка или она соответствует регулярному выражению.
На самом деле не стоит публиковать как собственный ответ, но комбинация read hdr; echo "$hdr" также будет работать вместо head -1, поскольку read не выполняет буферизацию, считывая по одному байту за раз, пока не увидит новую строку.
Sed (1) также может использоваться для фильтрации вывода в этом случае:
ps aux | sed -n '1p; /root/p'
-n: не выводить строку ввода на стандартный вывод после того, как к ней были применены все команды.
1p; "адрес" строки1, с 'p' для печати пробела шаблона
/root/p; "адрес" / regexp /, соответствующий "корню", с 'p' для печати пространства шаблона
Альтернатива:
ps aux | sed '1p; /root/p; d;'
Для некоторых систем может потребоваться ps -aux i.t. тире (-) перед опциями префикса. Системы Linux и * BSD этого не делают (не могу точно сказать, как себя ведет macOS, у меня нет такой системы, чтобы проверить).
Это больше вопрос библиотеки C и буферизации ввода-вывода. Во втором случае
head -1считывает буфер данных со стандартного ввода и распечатывает первую строку; остальное было проигнорировано.grepне смог увидеть данные, которые читалhead, и, по-видимому, не осталось ничего значимого. В первом случае не совсем понятно, что дает, но, вероятно, поведение было аналогичным, за исключением того, что на выходеps auxбыло больше строк данных после того, какheadпрочитал первое заполнение буфера, поэтомуgrepвыдал те строки, которые совпали после отсутствия неизвестное количество строк, прочитанныхhead.