Обманите приложение, думая, что его выступление - это терминал, а не труба

Я пытаюсь сделать противоположное

Обнаруживать, является ли 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