Обманите приложение, думая, что его выступление - это терминал, а не труба
Я пытаюсь сделать противоположное
Обнаруживать, является ли stdin терминалом или трубой?
Я запускаю приложение, изменяющее его выходной формат, потому что он обнаруживает канал на stdout, и я хочу, чтобы он думал, что это интерактивный терминал, чтобы я получал одинаковый вывод при перенаправлении.
Я думал, что обернуть его в сценарий expect
или использовать proc_open()
в PHP сделает это, но это не так.
Есть идеи?
Ответы
Ответ 1
Ага!
Команда script
делает то, что мы хотим...
script --return --quiet -c "[executable string]" /dev/null
Делает трюк!
Usage:
script [options] [file]
Make a typescript of a terminal session.
Options:
-a, --append append the output
-c, --command <command> run command rather than interactive shell
-e, --return return exit code of the child process
-f, --flush run flush after each write
--force use output file even when it is a link
-q, --quiet be quiet
-t[<file>], --timing[=<file>] output timing data to stderr or to FILE
-h, --help display this help
-V, --version display version
Ответ 2
Основываясь на решении Криса, я придумал следующую небольшую вспомогательную функцию:
faketty() {
script -qfc "$(printf "%q " "[email protected]")" /dev/null
}
Причудливый вид printf
необходим для правильного расширения аргументов сценария в [email protected]
при защите, возможно, цитируемых частей команды (см. Пример ниже).
Применение:
faketty <command> <args>
Пример:
$ python -c "import sys; print sys.stdout.isatty()"
True
$ python -c "import sys; print sys.stdout.isatty()" | cat
False
$ faketty python -c "import sys; print sys.stdout.isatty()" | cat
True
Ответ 3
unbuffer script, который поставляется с Ожидать должен обрабатывать это нормально. Если нет, приложение может смотреть на что-то другое, кроме того, к чему подключен его выход, например. что для переменной среды TERM установлено значение.
Ответ 4
Я не знаю, справляется ли это с PHP, но если вам действительно нужен дочерний процесс для просмотра TTY, вы можете создать PTY.
В C:
#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>
#include <unistd.h>
#include <pty.h>
int main(int argc, char **argv) {
int master;
struct winsize win = {
.ws_col = 80, .ws_row = 24,
.ws_xpixel = 480, .ws_ypixel = 192,
};
pid_t child;
if (argc < 2) {
printf("Usage: %s cmd [args...]\n", argv[0]);
exit(EX_USAGE);
}
child = forkpty(&master, NULL, NULL, &win);
if (child == -1) {
perror("forkpty failed");
exit(EX_OSERR);
}
if (child == 0) {
execvp(argv[1], argv + 1);
perror("exec failed");
exit(EX_OSERR);
}
/* now the child is attached to a real pseudo-TTY instead of a pipe,
* while the parent can use "master" much like a normal pipe */
}
На самом деле у меня создалось впечатление, что expect
сам создает PTY.
Ответ 5
Ссылаясь на предыдущий ответ, в Mac OS X можно использовать "script", как показано ниже...
script -q /dev/null commands...
Но, поскольку он может изменить код возврата с "\n" на "\ r\n", мне нужно было запустить это.
script -q /dev/null commands... | perl -pe 's/\r\n/\n/g'
Если между этими командами есть какая-то трубка, вам нужно сбросить stdout. например:
script -q /dev/null commands... | ruby -ne 'print "....\n";STDOUT.flush' | perl -pe 's/\r\n/\n/g'
Ответ 6
Anywhere Python установлен,
echo fakepassword | python -c 'import pty, sys; pty.spawn(sys.argv[1:])' ssh
Ответ 7
Слишком новое, чтобы прокомментировать конкретный ответ, но я подумал, что буду следить за функцией faketty
, опубликованной в ingomueller-net выше, так как недавно она мне помогла.
Я обнаружил, что это создало файл typescript
, который мне не нужен/нуждался, поэтому я добавил /dev/null в качестве целевого файла script:
function faketty { script -qfc "$(printf "%q " "[email protected]")" /dev/null ; }
Ответ 8
Также в примерный код книги "Расширенное программирование в среде UNIX, второе издание" включена программа pty!!
Здесь как скомпилировать pty в Mac OS X:
http://codesnippets.joyent.com/posts/show/8786
Ответ 9
Надеюсь, помочь кому-то:
Я наткнулся на этот вопрос, пытаясь добавить ловушку git pre-commit, запускающую тесты BeHat внутри моего контейнера:
#!/bin/sh
rc=0
behat=0
EXEC_BEHAT='docker-compose exec phpfpm sh -c "vendor/bin/behat"'
script -q --return -c "${EXEC_BEHAT}" /dev/null
behat=$?
if [[ $behat != 0 ]]; then
echo "
██████╗ ███████╗██╗ ██╗ █████╗ ████████╗ ███████╗ █████╗ ██╗██╗ ██╗
██╔══██╗██╔════╝██║ ██║██╔══██╗╚══██╔══╝ ██╔════╝██╔══██╗██║██║ ██║
██████╔╝█████╗ ███████║███████║ ██║ █████╗ ███████║██║██║ ██║
██╔══██╗██╔══╝ ██╔══██║██╔══██║ ██║ ██╔══╝ ██╔══██║██║██║ ╚═╝
██████╔╝███████╗██║ ██║██║ ██║ ██║ ██║ ██║ ██║██║███████╗██╗
╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝
"
rc=1
fi
[ $rc -ne 0 ] && exit 1
exit 0