Чем запуск `less` отличается от запуска `cat` в ZSH в отношении использования альтернативного экрана и приостановки фона

В моей ОС по умолчанию ZSH имеет -tostop (или tty?).

Это позволяет фоновым процессам выводить данные в оболочку, когда у них есть вывод.

Следовательно:

> stty -tostop
> echo 'random' >/tmp/random
> cat /tmp/random &
[1] 7588
random
[1]  + 7588 done       cat /tmp/random

Соответственно:

> stty tostop
> echo 'random' >/tmp/random
> cat /tmp/random &
[1] 3888
[1]  + 3888 suspended (tty output)  cat /tmp/random

Почитав документацию и немного поэкспериментировав, я обнаружил, что в ZSH есть 4 типа приостановленных процессов (это можно увидеть, используя kill -$SIGNAL $PID ; jobs):

job state              - signal that gives you job state
suspended              - SIGTSTP
suspended (signal)     - SIGSTOP
suspended (tty input)  - SIGTTIN
suspended (tty output) - SIGTTOU

Это будет означать, что процесс 3888 получает сигнал SIGTTOU.

Все это имеет смысл.

Теперь мой вопрос в том, почему less не зависит от stty tostop или stty -tostop?

> stty tostop
> less /tmp/random &
[1] 6300
[1]  + 6300 suspended (tty output)  less --LONG-PROMPT --chop-long-lines /tmp/random

> stty -tostop
> less /tmp/random &
[1] 4808
[1]  + 4808 suspended (tty output)  less --LONG-PROMPT --chop-long-lines /tmp/random

Как вы можете видеть в обоих случаях, less всегда приостанавливается в фоновом режиме.

Теперь я знаю о less -X, а также о функции альтернативного экрана, которая есть в эмуляторах терминала. На самом деле, вы можете запустить две вышеуказанные команды с помощью less -X, и это приведет к такому же приостановке. Несмотря на то, что -X запрещает использование альтернативных экранов, less все равно получает suspended (tty output)!

Что я хочу знать, так это реальную механику того, как less всегда приостанавливается с suspended (tty output), даже когда tostop переключается, и даже когда -X тоже переключается. Как может оболочка всегда отправлять SIGTTOU в less, если нет другого способа приостановить less.


person CMCDragonkai    schedule 23.04.2016    source источник
comment
Альтернативный экран не связан с обработкой сигналов в less.   -  person Thomas Dickey    schedule 23.04.2016


Ответы (1)


(вы не указываете свою ОС, но этот ответ основан на Linux)

Используя strace, вы можете увидеть, как stty выполняет ioctl для fd 0 (stdin), переключая один бит в значении c_lflag структуры termios.

strace также показывает, что less откроет /dev/tty и выдаст на него ioctl, чтобы изменить c_lflag.

Таким образом, less просто делает то же самое, что и stty tostop, прежде чем что-либо выводить.

person mvds    schedule 23.04.2016
comment
Я понимаю. Когда вы говорите fd 0 (stdin), вы имеете в виду стандартный ввод самой оболочки? В противном случае, какой стандартный ввод вы имеете в виду? Поэтому, когда less открывает файл, он фактически открывает /dev/tty для отправки туда вывода, и вы также выполняете ioctl для него. Когда less открывает /dev/tty, это подключение к стандартному вводу оболочки? - person CMCDragonkai; 24.04.2016
comment
fd 0 оболочки — это тот же fd 0 дочерних процессов, если только вы не перенаправляете его ввод. /dev/tty является управляющим терминалом процесса, поэтому большую часть времени он равен fd 0 оболочки, но если вы подключите fd 0 к файлу (скажем, less .profile < /dev/null), вы увидите, что less по-прежнему получает ввод с клавиатуры через /dev/tty. Однако, если вы перенаправите вывод less на что-то не tty (скажем, less .profile > /dev/null), он заметит (используя isatty(1), который попытается ioctl() его) и не откроет /dev/tty, а также проигнорирует стандартный ввод. (и вести себя как cat) - person mvds; 24.04.2016
comment
strace — ваш друг (в linux) — он показывает все системные вызовы и, следовательно, раскрывает все действия процесса, относящиеся к внешнему миру. Просто откройте оболочку, чтобы провести свои эксперименты stty и less, и отследите эту оболочку с другого терминала, используя strace -p PID -ff -o filename -s 10240 -v или аналогичный, что создаст отдельный выходной файл с именем filename.PID для каждого дочернего процесса. Чтобы увидеть внутреннюю работу процесса, используйте ltrace или отладчик. - person mvds; 24.04.2016