Как заставить команду думать, что ее вывод идет в терминал

38

При наличии команды, которая меняет свое поведение, когда ее вывод поступает на терминал (например, производит цветной вывод), как этот вывод может быть перенаправлен в конвейер при сохранении измененного поведения? Для этого должна быть полезность, о которой я не знаю.

Некоторые команды, например grep --color=always, имеют флажки параметров для принудительного поведения, но вопрос заключается в том, как обойти программы, которые полагаются исключительно на тестирование своего дескриптора выходного файла.

Если это имеет значение, моя оболочка bashна Linux.

эмир
источник
Вы должны знать, как команда проверяет свой дескриптор выходного файла и каким-то образом возвращать результаты в соответствии с результатами, которые будут видны из выходного терминала.
Эндрю Хенле

Ответы:

21

Вы можете получить то, что вам нужно, используя unbuffer.

unbufferэто tcl/ expectскрипт. Посмотрите на источник, если хотите. Также обратите внимание на раздел CAVEATS в man.

Также обратите внимание, что он не выполняет псевдонимы, такие как:

alias ls='ls --color=auto'

если только не добавить трюк, как отметил Стефан Шазелас:

Если вы сделаете alias unbuffer='unbuffer '(обратите внимание на завершающий пробел), то псевдонимы будут расширены после unbuffer.

Runium
источник
Обратите внимание на подтвержденные псевдонимы - он также не будет работать с другими конструкциями оболочки, такими как встроенные функции и функции.
Амир
4
Если вы сделаете alias unbuffer='unbuffer '(обратите внимание на завершающий пробел), то псевдонимы будут расширены после unbuffer.
Стефан Шазелас
unbufferэто! sudo apt install expect- Это было неясно.
loxaxs
22

История наборов инструментов

Вы не первый человек, который хочет такой инструмент. Люди давно хотят таких инструментов. И они существовали почти так же долго.

Самым ранним инструментом для такого рода вещей был пакет «pty» Дэниела Дж. Бернштейна, который Рич Зальц назвал «ножом Гинсу», который Бернштейн написал в конце 1990-х для того, чтобы обмануть nethack (sic!). Версия 4 пакета «pty» была опубликована в 1992 году comp.sources.unix(том 25, выпуск 127–135). Это все еще можно найти в World Wide Web. Пол Vixie описал это в то время:

Что я могу сказать? Он нарезает ломтиками, нарезает кубиками, моет посуду, гуляет с собакой. Это «просто работает», что означает, что если вы будете следовать указаниям, вы получите рабочий пакет без каких-либо выдергивания волос, скрежета зубов или других стандартных действий по переносу.

Позднее Бернштейн обновил это, когда-то в 1999-04-07 или ранее, пакетом "ptyget", который он объявил:

Я собрал новый псевдо-tty распределитель, ptyget. Альфа-версия на ftp://koobera.math.uic.edu/pub/software/ptyget-0.50.tar.gz. Есть список рассылки ptyget; чтобы присоединиться, отправьте пустое сообщение djb-ptyget-requ...@koobera.math.uic.edu. Я разработал интерфейс ptyget с нуля. Это гораздо более модульно, чем pty; Базовый интерфейс pty теперь разделен на три части:

  • ptyget: крошечная низкоуровневая программа - единственная программа setuid в пакете - которая выделяет новую псевдо-tty и передает ее в программу по вашему выбору
  • ptyspawn: еще одна небольшая программа, которая запускает дочерний процесс под псевдотермией, ожидает его завершения и отслеживает остановки
  • ptyio: еще одна, чуть больше, программа, которая перемещает данные назад и вперед

Записан старый нож ptyГинсу ptybandage, что является синонимом ptyget ptyio -t ptyspawn; pty -dдля присоединения сетевых программ к псевдо-tys теперь пишется ptyrun, что является синонимом для ptyget ptyio ptyspawn; и nobufявляется синонимом для ptyget ptyio -r ptyspawn -23x. Я разделил функции управления сессиями на отдельный пакет.

Этот отдельный пакет был пакетом "sess".

Кстати, «ptyget» отличается тем, что служит примером очень ранней версии и одного из немногих опубликованных примеров собственной, никогда не публикуемой системой сборки «redo» Берштейна. dependonявляется явным предшественником redo-ifchange.

использование

ptybandage

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

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

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

ptyrun

ptyrunэто то, что люди обычно хотят на сетевых серверах TCP. Его основной сценарий использования - это среды удаленного выполнения, в которых сами терминалы не настроены, и запускаются программы, которые не работают должным образом, когда нет терминала.

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

Доступные наборы инструментов

Дрю Нельсон публикует "pty" версию 4 и "ptyget".

Пол Джарк публикует фиксированную версию ptyget, в которой предпринята попытка обработать специфичные для операционной системы псевдо-терминальные устройства ioctl в оригинале, которые операционные системы фактически больше не предоставляют.

Пакет с исходным кодом nosh поставляется с рабочими файлами ptybandangeи ptyrunсценариями, которые используют execlineинструмент Лорана Беркота и собственные команды управления псевдо-терминалом пакета nosh . Начиная с версии nosh 1.23 они доступны предварительно упакованы в пакет nosh-terminal-extras. (Более ранние версии предоставляли их только людям, которые создавали из исходников.)

Несколько примеров использования

Юрген Оскам (Jurjgen Oskam), использующий ptybandageв AIX для передачи ввода из документа здесь в программу, которая открывается явным образом, и читает свой управляющий терминал для запроса пароля:

$ ptybandage dsmadmc << EOF> uit.txt
joskam
пароль
сеанс запроса
процесс запроса
уволиться
EOF

Энди Брэдфорд использует ptyrunOpenBSD под daemontools и ucspi-tcp, чтобы сделать bgplgshинтерактивную программу управления маршрутизатором доступной через сеть, заставляя ее думать, что она общается с терминалом:

#! / Bin / ш
Exec 2> & 1
exec envuidgid rviews tcpserver -vDRHl0 0 23 ptyrun / usr / bin / bgplgsh

дальнейшее чтение

JdeBP
источник
Спасибо за урок истории, но предлагаемые вами инструменты недоступны в современном дистрибутиве Linux и, следовательно, бесполезны.
Амир
4
Там куча гиперссылок и целая часть ответа , посвященной где инструменты наиболее определенно являются доступны.
JdeBP
1
Каково ваше мнение expect?
CMCDragonkai
20

Вы можете использовать socat, чтобы запустить процесс с подключенным pty , и заставить socat подключить другой конец pty к файлу. Какой AFAIU именно то, что вы спросили:

socat EXEC:"my-command",pty GOPEN:mylog.log

Этот метод приведет к тому, что isattyвызванный метод my-commandвернется, trueи процесс, который полагается только на это, будет одурачен для вывода управляющих кодов. Обратите внимание, что некоторые процессы (в частности grep) также проверяют значение TERMпеременной среды, поэтому вам может потребоваться установить для нее что-то разумное, например"xterm"

Guss
источник
13

Здесь также есть хорошее решение, опубликованное здесь на Super User от KarlC :

Скомпилируйте небольшую общую библиотеку:

echo "int isatty(int fd) { return 1; }" | gcc -O2 -fpic -shared -ldl -o isatty.so -xc -

Затем скажите вашей команде, чтобы isatty(3)динамически загружать это переопределение:

LD_PRELOAD=./isatty.so mycommand

Это может не сработать для каждой команды, может даже неожиданно сломать некоторые, но, вероятно, сработает в большинстве случаев.

эмир
источник
2
Для пользователей MacOS вы можете получить то же поведение, используяDYLD_INSERT_LIBRARIES=./isatty.so DYLD_FORCE_FLAT_NAMESPACE=y mycommand
Кристофер Шроба
12

Как насчет использования script(1)?

Например:

script -q -c 'ls -G' out_file

Сохраните lsвывод в out_fileсохраненных цветовых кодах.

Саги
источник
Это не работает здесь. Как цвета сохраняются? Есть ли инструмент, который я должен использовать для вывода out_fileс его цветами?
Кира
1
@Kira для просмотра файлов с escape-последовательностями ANSI, я использую less -R. В этом случае, однако, я хотел, чтобы вывод продолжался в конвейере, который в конечном итоге оказался в моем терминале. Используя catдля иллюстрации, это было что-то вроде script -q -c 'ls -G' /dev/null | cat, который полностью подавляет typescriptфайл, оставляя только вывод программы.
Амир
Чтобы избежать создания файла, просто используйте dash ( -) в качестве scriptвыходного файла, например:script -q -c 'ls -G' -
Franklin Piat
0

Основываясь на ответе @ Amir , вот скрипт, который генерирует и затем включает библиотеку во время выполнения:

#!/bin/bash
set -euo pipefail

function clean_up {
  trap - EXIT # Restore default handler to avoid recursion
  [[ -e "${isatty_so:-}" ]] && rm "$isatty_so"
}
# shellcheck disable=2154 ## err is referenced but not assigned
trap 'err=$?; clean_up; exit $err' EXIT HUP INT TERM

isatty_so=$(mktemp --tmpdir "$(basename "$0")".XXXXX.isatty.so)
echo "int isatty(int fd) { return 1; }" \
  | gcc -O2 -fpic -shared -ldl -o "$isatty_so" -xc -
# Allow user to SH=/bin/zsh faketty mycommand
"${SH:-$SHELL}" -c 'eval $@' - LD_PRELOAD="$isatty_so" "$@"
Том Хейл
источник