Можете ли вы обмануть isatty И войти в stdout и stderr отдельно?
Таким образом, вы хотите регистрировать stdout и stderr (отдельно) процесса или подпроцесса, без вывода результатов, отличных от того, что вы увидите в терминале, если вы ничего не регистрировали.
Кажется довольно просто нет? Ну, к сожалению, кажется, что может быть невозможно написать общее решение для этой проблемы, которое работает на любом данном процессе ...
ФонПеренаправление каналов - это один из методов разделения stdout и stderr, что позволяет вам регистрировать их по отдельности. К сожалению, если вы измените stdout / err на канал, процесс может обнаружить, что канал не является tty (потому что он не имеет ширины / высоты, скорости передачи и т. Д.) И может соответствующим образом изменить свое поведение. Зачем менять поведение? Ну, некоторые разработчики используют функции терминала, которые не имеют смысла, если вы записываете в файл. Например, для загрузки полос часто требуется, чтобы курсор терминала был перемещен назад к началу строки, а предыдущая строка загрузки была перезаписана полосой новой длины. Также цвет и вес шрифта могут отображаться в терминале, но в плоском файле ASCII они не могут. Если бы вы записали стандартный вывод такой программы непосредственно в файл, этот вывод содержал бы все escape-коды терминала ANSI, а не должным образом отформатированный вывод. Поэтому разработчик реализует какую-то проверку «isatty» перед записью чего-либо в stdout / err, поэтому он может дать более простой вывод для файлов, если эта проверка возвращает false.
Обычное решение здесь состоит в том, чтобы обманом заставить такие программы думать, что каналы на самом деле являются ttys, используя pty - двунаправленный канал, который также имеет ширину, высоту и т. Д. Вы перенаправляете все входы / выходы процесса в этот pty, и это обманывает процесс, заставляющий думать, что он разговаривает с реальным терминалом (и вы можете записать его прямо в файл). Единственная проблема в том, что, используя один pty для stdout и stderr, мы больше не можем различать эти два.
Таким образом, вы можете попробовать разные pty для каждого канала - один для стандартного ввода, один для стандартного вывода и один для stderr. Хотя это будет работать в 50% случаев, многие процессы, к сожалению, проводят дополнительные проверки перенаправления, чтобы убедиться, что выходные пути stdout и stderr (/ dev / tty000x) совпадают. Если это не так, должно быть перенаправление, таким образом, они дают вам такое же поведение, как если бы вы передавали stderr и stdout без pty.
Вы можете подумать, что эта чрезмерная проверка на перенаправление является редкостью, но, к сожалению, на самом деле она довольно распространена, потому что многие программы повторно используют другой код для проверки, как этот фрагмент кода, найденный в OSX:
http://src.gnu-darwin.org/src/bin/stty/util.c
ВызовЯ думаю, что лучший способ найти решение - это вызов. Если кто-то может запустить следующий скрипт (в идеале через Python, но на этом этапе я возьму что-нибудь) таким образом, что stdout и stderr регистрируются отдельно, и вам удалось обмануть его, думая, что он был выполнен через tty, Вы решаете проблему :)
#!/usr/bin/python
import os
import sys
if sys.stdout.isatty() and sys.stderr.isatty() and os.ttyname(sys.stdout.fileno()) == os.ttyname(sys.stderr.fileno()):
sys.stdout.write("This is a")
sys.stderr.write("real tty :)")
else:
sys.stdout.write("You cant fool me!")
sys.stdout.flush()
sys.stderr.flush()
Обратите внимание, что решение должно действительно работать длялюбой процесс, а не только этот код конкретно. Перезапись модуля sys / os и использование LD_PRELOAD - очень интересные способы справиться с этой задачей, но они не решают суть проблемы :)