меньше file1 file2 | кот - почему это работает?

21

Когда я использую, less file1 file2я получаю оба файла, показанные в «меньшем буфере просмотра», но less file1 file2 | catпечатает содержимое обоих файлов, добавленных в стандартный вывод. Как less узнает, должен ли он отображать «менее просмотрщик буфера» или выводить в stdout для следующей команды? Какой механизм используется для этого?

TFH
источник

Ответы:

30

lessпечатает текст на стандартный вывод стандартный выход

  • на терминал (/ dev / tty?) и открывает средство просмотра буфера по умолчанию
  • через канал при передаче его в другую программу, используя | ( less text | cut -d: -f1)
  • в файл при перенаправлении его с помощью> ( less text > tmp)

Существует функция C, называемая isa tty, которая проверяет, идет ли вывод в tty (меньше 4.81, main.c, строка 112). Если это так, он использует просмотрщик буфера, иначе он ведет себя как cat.

В Bash вы можете использовать тест (см. man test)

  • -t FD дескриптор файла FD открывается на терминале
  • -p ФАЙЛ существует и является именованным каналом

Пример:

[[ -t 1 ]] && \
    echo 'STDOUT is attached to TTY'

[[ -p /dev/stdout ]] && \
    echo 'STDOUT is attached to a pipe'

[[ ! -t 1 && ! -p /dev/stdout ]] && \
    echo 'STDOUT is attached to a redirection'
Майкл Д.
источник
1
@tfh Если STDOUT не присоединен к каналу или перенаправлению, правильно, что они не печатают, что STDOUT присоединен к каналу или перенаправлению. Поместите все три в сценарий. Вызов bash script.sh, bash script.sh | cat, bash script.sh > fileи посмотреть , что вывод , который вы получите.
HVd
1
stdoutэто не то, что можно записать в файл. Это то, что вам write() нужно . lessне нужно ничего делать по-разному, в зависимости от того, является ли его вывод файлом, каналом, сокетом или блочным устройством, или чем-то еще. Имеет значение только то, что это не tty, поэтому он просто ведет себя как cat. (Я предполагаю, что вы знали это и просто выбрали неправильные слова, чтобы объяснить это, но я думал, что укажу это другим читателям).
Питер Кордес
Таким образом, вы имеете в виду, что в моем конкретном вопросе задача менее вести себя как кошка - или более общая: вести себя как следующая команда в конвейере. Из того, что я понял, я не могу предположить, что точно такое же поведение реализовано и в другом инструменте.
TFH
@tfh: нет, lessне "выяснить", что catбудет дальше. Это просто ведет себя как catнезависимо от того, что это дальше, если это стандартный вывод не tty.
Питер Кордес
@MichaelD .: спасибо, исправил мой ответ. Я только догадывался, что lessможно пойти дальше и использовать один TCGETS, чтобы получить размеры терминала или обнаружить, что это не tty, но, видимо, я догадался неправильно.
Питер Кордес
6

lessпроверяет, stdoutявляется ли он терминалом, и ведет себя так, как catесли бы это не было (копирует стандартный ввод в стандартный вывод до EOF).

Эта функция позволяет вам писать скрипты или программы, которые всегда отправляют свои выходные данные (например, --helpвыходные данные), в lessто же время позволяя легко перенаправить файл. Было бы плохо, если бы some_command --fullhelp > help.txtвсе еще ждали пробел на stdin, чтобы пролистать текст или что-то еще. Некоторые команды (например man) проверяют свой собственный вывод, чтобы решить, отправлять ли свой вывод через пейджер или нет. Если вы бежите man ls > ls.txt, он никогда не вызывает вашу $PAGER.

lessПодобное кошке поведение удобно, если вы забыли отредактировать его из однострочного текста при добавлении дополнительных этапов в конвейер.


lessНужно выяснить размеры терминала (размер экрана, узнать, сколько строк показывать одновременно). ioctl(2)Он использует по stdoutвернется ENOTTY на нетерминале, так что он не может избежать обработок нетерминального дела в любом случае. lessфактически использует isatty(3)перед проверкой размеров терминала, но isattyработает, используя to-only ioctl и проверяя отсутствие ошибок.

Даже такой простой пейджер more(1)(по крайней мере, версия util-linux) имеет эту функцию, потому что это, вероятно, простейшее вменяемое поведение для реализации в этом случае.


Обратите внимание, что когда вы что-то передаете less (например grep foo bar.txt | less), оно должно открываться /dev/ttyдля ввода с клавиатуры. (Вы можете видеть это с этим echo foo | strace less).

Питер Кордес
источник