2009-09-09 11 views
109

sto cercando di fare il contrario diDolcetto un'applicazione nel pensare suo stdout è un terminale, non un tubo

Detect if stdin is a terminal or pipe?

sto correndo un'applicazione che cambia il suo formato di output perché esso rileva un pipe su stdout, e voglio che pensi che sia un terminale interattivo in modo da ottenere lo stesso output durante il reindirizzamento.

Stavo pensando che inserirlo in uno script expect o utilizzando uno proc_open() in PHP lo farebbe, ma non è così.

Qualche idea là fuori?

+7

Does http: //empty.sf .net aiuto? – ephemient

+1

@ephemient: avrebbe dovuto essere una risposta. Grande utilità a proposito ... – neuro

+0

La domanda parla di stdout ma il titolo parla di stdin. Penso che il titolo sia sbagliato. –

risposta

14

Non so se è possibile farlo da PHP, ma se hai davvero bisogno che il processo figlio veda un TTY, puoi creare un PTY.

In 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 */ 
} 

Mi è stato effettivamente l'impressione che expect stesso non crea un PTY, però.

+0

Sai come eseguire nettop come processo figlio su mac os x? Voglio ottenere l'output di nettop nella mia app. Ho provato a usare forkpty, ma ancora non ho potuto eseguire nettop con successo. –

138

Aha!

Il comando script fa quello che vogliamo ...

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

fa il trucco!

+1

+1: appena inciampi sul problema con una lib che fa l'inizializzazione statica. Un recente cambiamento in Fedora 12 ha fatto fallire l'init quando l'ex lanched non era in una tty. Il tuo trucco funziona perfettamente. L'ho preferito a unbuffer dato che lo script è installato di default! – neuro

+0

'script' è persino disponibile in [BusyBox] (http://busybox.net/downloads/BusyBox.html)! – dolmen

+7

Se si vuole inserirlo in qualcosa di interattivo, come 'less -R', dove l'input del terminale va a' less -R', allora è necessario qualche trucco extra. Ad esempio, volevo una versione colorata di 'stato git | less'. Devi passare '-R' a un valore inferiore per rispettare i colori, e devi usare' script' per ottenere 'git status' per l'output del colore. Ma non vogliamo che 'script' mantenga la proprietà della tastiera, vogliamo che questo vada a' less'. Quindi lo uso ora e funziona bene: '0 <& - script -qfc" git status "/ dev/null | meno -R'. Quei primi pochi caratteri chiudono stdin per questo comando. –

15

Lo script unbuffer fornito con Expectdeve essere gestito da. In caso contrario, l'applicazione potrebbe guardare qualcosa di diverso da ciò a cui è collegato il suo output, ad es. a cosa è impostata la variabile d'ambiente TERM.

+0

Grazie, risolto il collegamento ora. –

0

C'è anche un programma pty incluso nel codice di esempio del libro "Programmazione avanzata in ambiente UNIX, seconda edizione"!

Ecco come compilare Pty su Mac OS X:

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

+2

Collegamento interrotto. :( – dolmen

+0

Errore davvero strano, anche: * Veloce errore: dominio sconosciuto: codesnippets.joyent.com. Verifica che questo dominio sia stato aggiunto a un servizio. * –

12

riferimento precedente risposta, su Mac OS X, "script" può essere utilizzato come qui di seguito ...

script -q /dev/null commands... 

Ma, poiché potrebbe cambiare il codice di ritorno da "\ n" a "\ r \ n", avevo bisogno di correre così.

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

Se tra questi comandi è presente una pipe, è necessario svuotare lo stdout. per esempio:

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

Grazie per la sintassi OS X, ma, a giudicare dall'istruzione Perl , sembra che tu volessi dire che cambia le istanze di "\ r \ n" in "\ n", non il contrario, corretto? – mklement0

+0

Hai ragione, grazie! Ho risolto il problema. –

44

Sulla base di Chris' solution, mi si avvicinò con la seguente funzione di supporto poco:

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

L'eccentrico cercando printf è necessario espandere correttamente gli argomenti dello script in [email protected], proteggendo le parti eventualmente citati del comando (vedi esempio sotto).

Usage:

faketty <command> <args> 

Esempio:

$ 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

Probabilmente vuoi usare l'opzione '--return', se la tua versione di' script' ce l'ha, per preservare il codice di uscita del processo figlio. – jwd

+2

Raccomando di cambiare questa funzione in questo modo: 'function faketty {script -qfc" $ (printf "% q" "$ @") "/ dev/null; } ' In caso contrario, in molti casi verrà creato un file denominato' typescript' ogni volta che viene eseguito un comando. – w0rp

14

Ovunque Python è installato,

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

troppo nuovo per commentare la risposta specifica, ma ho pensato Seguirò sulla funzione faketty inserita da ingomueller-net sopra poiché recentemente mi ha aiutato.

ho scoperto che questo è stato la creazione di un file typescript che non volevo/bisogno così ho aggiunto/dev/null come il file di destinazione script:

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

Problemi correlati