Come indurre un comando a pensare che il suo output stia andando su un terminale


38

Dato un comando che cambia il suo comportamento quando il suo output sta andando su un terminale (ad es. Produce output colorato), come può essere reindirizzato a un output in una pipeline mantenendo il comportamento modificato? Deve esserci un'utilità per questo, di cui non sono a conoscenza.

Alcuni comandi, ad esempio grep --color=always, hanno flag di opzione per forzare il comportamento, ma la domanda è come aggirare i programmi che si basano esclusivamente sul test del descrittore del file di output.

Se è importante, la mia shell è bashsu Linux.


Devi sapere come il comando verifica il suo descrittore di file di output e in qualche modo restituire risultati coerenti con i risultati che verrebbero visualizzati da un terminale di output.
Andrew Henle,

Risposte:


21

Puoi ottenere ciò di cui hai bisogno usando unbuffer.

unbufferè un tcl/ expectscript. Guarda la fonte se vuoi. Nota anche la sezione CAVEATS in man.

Si noti inoltre che non esegue alias come:

alias ls='ls --color=auto'

a meno che uno non aggiunga un trucco come notato da Stéphane Chazelas:

Se fai un alias unbuffer='unbuffer '(nota lo spazio finale), gli alias verranno espansi dopo unbuffer.


Nota sugli alias riconosciuti - inoltre non funzionerà con nessun altro costrutto shell come builtin e funzioni.
Amir,

4
Se fai un alias unbuffer='unbuffer '(nota lo spazio finale), gli alias verranno espansi dopo unbuffer.
Stéphane Chazelas,

unbufferè! sudo apt install expect- Non era chiaro.
Loxaxs

22

Una storia di set di strumenti

Non sei la prima persona a desiderare un simile strumento. Le persone desiderano tali strumenti da 30 anni. E sono esistiti anche per così tanto tempo.

Il primo strumento per questo genere di cose fu il pacchetto "pty" di Daniel J. Bernstein, descritto da Rich Salz come un "coltello Ginsu", che Bernstein scrisse alla fine degli anni '90 per imbrogliare a nethack (sic!). La versione 4 del pacchetto "pty" è stata pubblicata nel 1992 comp.sources.unix(volume 25 numeri da 127 a 135). È ancora localizzabile sul World Wide Web. Paul Vixie lo descrisse all'epoca:

Cosa posso dire? Taglia, taglia, lava i piatti, porta a spasso il cane. "Funziona", il che significa che se segui le istruzioni otterrai un pacchetto di lavoro senza strappi di capelli o digrignamento dei denti o altre attività di porting standard.

Bernstein in seguito lo aggiunse, qualche volta prima o prima del 1999-04-07, con un pacchetto "ptyget", che annunciò:

Ho messo insieme un nuovo allocatore pseudo-tty, ptyget. Una versione alfa è a ftp://koobera.math.uic.edu/pub/software/ptyget-0.50.tar.gz. C'è una mailing list di ptyget; per partecipare, inviare un messaggio vuoto a djb-ptyget-requ...@koobera.math.uic.edu. Ho progettato l'interfaccia di ptyget da zero. È molto più modulare di pty; l'interfaccia pty di base ora è stata divisa in tre pezzi:

  • ptyget: un piccolo programma di basso livello - l'unico programma setuid nel pacchetto - che alloca un nuovo pseudo-tty e lo passa al programma che preferisci
  • ptyspawn: un altro piccolo programma che esegue un processo figlio sotto pseudo-tty, in attesa che esca e in attesa di fermate
  • ptyio: un altro programma, leggermente più grande, che sposta avanti e indietro i dati

Il vecchio coltello Ginsu ptyè ora scritto ptybandage, che è sinonimo di ptyget ptyio -t ptyspawn; pty -d, per collegare programmi di rete a pseudo-tty, è ora scritto ptyrun, che è sinonimo di ptyget ptyio ptyspawn; ed nobufè sinonimo di ptyget ptyio -r ptyspawn -23x. Ho suddiviso le funzionalità di gestione della sessione in un pacchetto separato.

Quel pacchetto separato era il pacchetto "sess".

"ptyget" è, per inciso, noto per esemplificare una versione molto antica di, e una delle poche istanze pubblicate del sistema di build "redo" mai pubblicato da Berstein. dependonè un chiaro precursore di redo-ifchange.

uso

ptybandage

ptybandageè ciò che di solito le persone desiderano in una sessione di accesso. Il suo caso d'uso principale è rendere i programmi sensibili al fatto che i loro input, output o errori standard siano collegati ai terminali funzionino in questo modo anche se in realtà sono in pipeline di shell o se i loro descrittori di file standard vengono reindirizzati a file.

Ci vuole un comando da eseguire (che deve essere un comando esterno adeguato, ovviamente) e viene eseguito in modo tale che esso ritiene che il suo input, output e l'errore standard sono collegati a un terminale, collega quelli sui ptybandages' input, output ed errore standard originali.

Gestisce le sfumature dell'esecuzione sotto shell di controllo lavoro, assicurando che un carattere STOP del terminale non solo si fermi, ptybandagema fermi anche il programma in esecuzione collegato al terminale interno.

ptyrun

ptyrunè ciò che la gente di solito desidera nei server di rete TCP. Il suo caso d'uso principale sono gli ambienti di esecuzione remota che non hanno essi stessi impostato terminali, eseguendo programmi che non funzionano come desiderato quando non c'è terminale.

Non prevede di essere eseguito in una shell di controllo lavoro e se il comando in esecuzione riceve un segnale di arresto, viene semplicemente riavviato.

Set di strumenti disponibili

Dru Nelson pubblica sia "pty" versione 4 che "ptyget".

Paul Jarc pubblica una versione fissa di ptyget, che tenta di gestire l'originale dispositivo pseudo-terminale specifico del sistema operativo che i sistemi operativi non forniscono più.

Il pacchetto sorgente di nosh viene fornito con workalike ptybandangee ptyrunscript, che utilizzano lo execlinestrumento di Laurent Bercot e i comandi di gestione pseudo-terminali del pacchetto nosh . A partire dalla versione 1.23 di nosh, questi sono disponibili preconfezionati nel pacchetto nosh-terminal-extra. (Le versioni precedenti le fornivano solo alle persone che costruivano dalla fonte.)

Alcuni esempi usano

Jurjgen Oskam utilizza ptybandagesu AIX per inviare l' input da un documento qui a un programma che esplicitamente apre e legge il suo terminale di controllo per una richiesta di password:

$ ptybandage dsmadmc << EOF> uit.txt
joskam
parola d'ordine
sessione di query
processo di query
smettere
EOF

Andy Bradford utilizza ptyrunOpenBSD su demoneols e ucspi-tcp per rendere bgplgshaccessibile il programma di controllo del router interattivo tramite la rete, facendo pensare che stia parlando con un terminale:

#! / Bin / sh
exec 2> & 1
exec envuidgid rviews tcpserver -vDRHl0 0 23 ptyrun / usr / bin / bgplgsh

Ulteriori letture


Grazie per la lezione di storia, ma gli strumenti che suggerisci non sono disponibili in una moderna distribuzione Linux, quindi non utili.
Amir,

4
C'è un mucchio di collegamenti ipertestuali e un'intera sezione della risposta dedicata a dove gli strumenti sono sicuramente disponibili.
JdeBP,

1
Qual è la tua opinione su expect?
CMCDragonkai

20

È possibile utilizzare socat per avviare il processo con un pty connesso e ottenere socat per connettere l'altra estremità del pty a un file. Quale AFAIU è esattamente quello che hai chiesto:

socat EXEC:"my-command",pty GOPEN:mylog.log

Questo metodo farà sì che venga isattychiamato da my-commandreturn truee un processo che si basa solo su questo verrà ingannato dai codici di controllo dell'output. Si noti che alcuni processi (in particolare grep) controllano anche il valore della TERMvariabile d'ambiente, quindi potrebbe essere necessario impostarlo su qualcosa di ragionevole, come"xterm"


13

C'è anche una bella soluzione pubblicata qui su Super User da KarlC :

Compila una piccola libreria condivisa:

echo "int isatty(int fd) { return 1; }" | gcc -O2 -fpic -shared -ldl -o isatty.so -xc -

Quindi dì al tuo comando di caricare questa isatty(3)sostituzione in modo dinamico:

LD_PRELOAD=./isatty.so mycommand

Questo potrebbe non funzionare per tutti i comandi là fuori, potrebbe persino interromperne alcuni in modi inaspettati, ma probabilmente funzionerebbe nella maggior parte dei casi.


2
Per gli utenti MacOS, puoi ottenere lo stesso comportamento usandoDYLD_INSERT_LIBRARIES=./isatty.so DYLD_FORCE_FLAT_NAMESPACE=y mycommand
Christopher Shroba il

12

Che ne dici di usare script(1)?

Per esempio:

script -q -c 'ls -G' out_file

Salverà l' lsoutput out_filecon i codici colore conservati.


Questo non funziona qui. Come vengono conservati i colori? Esiste uno strumento che dovrei usare per produrre out_filecon i suoi colori?
Kira,

1
@Kira per la visualizzazione di file con sequenze di escape colore ANSI, io uso less -R. In questo caso, però, volevo che l'output continuasse nella pipeline, che alla fine è finito nel mio terminale. Usando a catscopo illustrativo, era qualcosa di simile script -q -c 'ls -G' /dev/null | cat, che sopprime del typescripttutto il file, lasciando solo l'output del programma.
Amir,

Per evitare di creare un file, basta usare un trattino ( -) come scriptfile di output, ad esempio:script -q -c 'ls -G' -
Franklin Piat

0

Basato sulla risposta di @ Amir , ecco uno script che genera e quindi include la libreria in fase di esecuzione:

#!/bin/bash
set -euo pipefail

function clean_up {
  trap - EXIT # Restore default handler to avoid recursion
  [[ -e "${isatty_so:-}" ]] && rm "$isatty_so"
}
# shellcheck disable=2154 ## err is referenced but not assigned
trap 'err=$?; clean_up; exit $err' EXIT HUP INT TERM

isatty_so=$(mktemp --tmpdir "$(basename "$0")".XXXXX.isatty.so)
echo "int isatty(int fd) { return 1; }" \
  | gcc -O2 -fpic -shared -ldl -o "$isatty_so" -xc -
# Allow user to SH=/bin/zsh faketty mycommand
"${SH:-$SHELL}" -c 'eval $@' - LD_PRELOAD="$isatty_so" "$@"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.