2009-09-09 2 views
109

Я пытаюсь сделать противоположныйTrick приложения, думая, его стандартный вывод является терминалом, а не труба

Detect if stdin is a terminal or pipe?

Я бег приложения, которое меняется его формат вывод, поскольку он обнаруживает pipe on stdout, и я хочу, чтобы он думал, что это интерактивный терминал, так что я получаю тот же результат при перенаправлении.

Я думал, что обертывание его в сценарий expect или использование proc_open() в PHP сделает это, но это не так.

Есть идеи?

+7

делает HTTP: //empty.sf .net help? – ephemient

+1

@ephemient: должен был быть ответ. Великая утилита, кстати, ... – neuro

+0

Вопрос об stdout, но в названии упоминается stdin. Я думаю, что название неверно. –

ответ

14

Я не знаю, можно ли это сделать с 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, хотя.

+0

Вы знаете, как запустить nettop в качестве дочернего процесса на mac os x? Я хочу получить вывод nettop в своем приложении. Я попытался использовать forkpty, но не смог успешно запустить nettop. –

138

Aha!

Команда script делает то, что мы хотим ...

script --return -c "[executable string]" /dev/null 

ли трюк!

+1

+1: просто спотыкайтесь о проблеме с lib, которая делает статическую инициализацию. Недавнее изменение в Fedora 12 привело к тому, что init завершился неудачей, когда exe lanched не был включен в tty. Твой трюк работает отлично. Я предпочел это над unbuffer, поскольку скрипт установлен по умолчанию! – neuro

+0

'script' даже доступен в [BusyBox] (http://busybox.net/downloads/BusyBox.html)! – dolmen

+7

Если вы хотите подключить его к чему-то интерактивному, например 'less -R', где терминал вводится в' less -R', тогда вам понадобится дополнительная интрижка. Например, мне нужна красочная версия 'git status | less'. Вам нужно передать '-R' меньше, чтобы он уважал цвета, и вам нужно использовать' script' для получения 'git status' для вывода цвета. Но мы не хотим, чтобы 'script' сохранял право собственности на клавиатуру, мы хотим, чтобы это перешло в' less'. Поэтому я использую это сейчас, и он хорошо работает: '0 <& - script -qfc" git status "/ dev/null | меньше -R'. Эти первые несколько персонажей закрывают stdin для этого комманда. –

15

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

+0

Спасибо, исправлена ​​ссылка сейчас. –

0

Существует также программа pty, включенная в пример кода книги «Расширенное программирование в среде UNIX, второе издание»!

Вот как собрать на PTY Mac OS X:

http://codesnippets.joyent.com/posts/show/8786

+2

Неработающая ссылка. :( – dolmen

+0

Действительно странная ошибка: * Быстрая ошибка: неизвестный домен: codesnippets.joyent.com. Пожалуйста, проверьте, что этот домен добавлен в службу. * –

12

Ссылаясь предыдущий ответ, на Mac OS X, "сценарий" может быть использован, как показано ниже ...

script -q /dev/null commands... 

Но, поскольку он может изменить код возврата с «\ n» на «\ r \ n», мне нужно было запустить это.

script -q /dev/null commands... | perl -pe 's/\r\n/\n/g' 

Если между этими командами есть какая-то трубка, вам необходимо сбросить стандартный вывод. например:

script -q /dev/null commands... | ruby -ne 'print "....\n";STDOUT.flush' | perl -pe 's/\r\n/\n/g' 
+1

Спасибо за синтаксис OS X, но, судя по вашему выражению Perl , кажется, вы хотели сказать, что он меняет экземпляры «\ r \ n» на «\ n», а не наоборот, правильно? – mklement0

+0

Вы правы. Спасибо, я исправил его. –

44

Основываясь на Chris' solution, я придумал следующий небольшой вспомогательной функции:

function faketty { script -qfc "$(printf "%q " "[email protected]")"; } 

Причудливый ищет 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 
+8

Возможно, вы захотите использовать параметр '--return', если ваша версия' script' имеет его, чтобы сохранить код выхода дочернего процесса. – jwd

+2

Я рекомендую изменить эту функцию следующим образом: 'function faketty {script -qfc" $ (printf "% q" "$ @") "/ dev/null; } ' В противном случае файл с именем' typescript' будет создан каждый раз во время выполнения команды. – w0rp

14

Anywhere установлен Python,

echo fakepassword | python -c 'import pty, sys; pty.spawn(sys.argv[1:])' ssh 
5

Слишком новый комментировать конкретный ответ, но я думал, Я буду следить на функции faketty, опубликованной ingomueller-net выше, так как она недавно мне помогла.

Я обнаружил, что это создает typescript файл, который я не хочу/нужно, поэтому я добавил/DEV/нуль в качестве целевого сценария файла:

function faketty { script -qfc "$(printf "%q " "[email protected]")" /dev/null ; }