Zsh può accedere allo stdout dell'ultimo programma eseguito?


15

Uso spesso findo locateper scoprire percorsi.

(~) locate foobar.mmpz
/home/progo/lmms/projects/foobar.mmpz

Il passo successivo è spesso aprire o manipolare in altro modo i file. In un caso felice come sopra, posso fare questo:

(~) ls `!!`
ls `locate foobar.mmpz`
/home/progo/lmms/projects/foobar.mmpz

Ma nessuno è troppo felice quando ci sono molte linee di output, alcune delle quali potrebbero non essere percorsi o qualcos'altro di quel tipo. Inoltre, rieseguire comandi potenzialmente dispendiosi non è neanche così elegante.

Ci sarebbe un modo per collegare zsh per memorizzare lo stdout in un array per successive manipolazioni? Dopotutto, è compito della shell reindirizzare gli stream all'utente. Sto pensando che potrebbe memorizzare la prima e l'ultima riga N in una variabile per un uso successivo immediato, come $?e altri.

Ok , questo è abbastanza bello: /unix//a/59704/5674 . Ora sto chiedendo il know-how di zsh (e il porting del codice su zsh) per attrezzare questo tipo di acquisizione dopo ogni linea di esecuzione.


Non è proprio il lavoro della shell reindirizzare il flusso all'utente. Le applicazioni scrivono il loro output sul dispositivo terminale, la shell non è coinvolta in questo.
Stéphane Chazelas,

@StephaneChazelas, ma è compito della shell, ad esempio, reindirizzare i flussi in file per richieste dell'utente. Ci sono anche ricette per zsh che colorano stderr in rosso per separarlo da stdout. Penso che ciò indichi il ruolo della shell nelle questioni di streaming.
unperson325680,

Sì, è possibile farlo utilizzando screeno scripte ganci precmd e preexec.
Stéphane Chazelas,

Risposte:


7

Non esiste alcuna funzione per catturare l'output dallo schermo sulla maggior parte degli emulatori di terminale. Mi sembra di ricordare l'autore di xterm (l'emulatore di terminale "di riferimento") affermando che sarebbe difficile da implementare. Anche se ciò fosse possibile, la shell dovrebbe tenere traccia di dove era stato l'ultimo prompt.

Quindi non ti sfuggirà a dover eseguire di nuovo il comando, a meno che non utilizzi un meccanismo manuale specifico per il terminale come copia-incolla con il mouse in xterm o con la tastiera in Schermo.

Sarebbe estremamente poco pratico che la shell acquisisca automaticamente l'output dei comandi, poiché non è in grado di distinguere tra comandi con complesse interazioni tra terminale e utente da comandi che generano semplicemente caratteri stampabili.

È possibile rieseguire il comando e acquisirne l'output. Esistono vari modi per farlo. Per rieseguire il comando, è possibile utilizzare:

  • !! sostituzione della cronologia - più comoda da digitare;
  • fc -e -, che può essere utilizzato in una funzione.

Per acquisire l'output, è possibile utilizzare la sostituzione dei comandi o una funzione come la seguente:

K () {
  lines=("${(f@)$(cat)}")
}
!! |K

Questo imposta l' linesarray sull'output del comando che viene reindirizzato al suo interno.


Così sia. Ora mi rendo conto alla luce delle buone spiegazioni che un approccio completamente automatico è troppo difficile come lo è, la seconda cosa migliore è qualcosa di simile al Ktuo.
unperson325680,

3

Ecco un primo taglio di qualcosa per mettere l'ultima riga di output in una variabile chiamata $lastline.

precmd () {                                                                                                                                                                                                        
    exec 2>&- >&-
    lastline=$(tail -1 ~/.command.out) 
    sleep 0.1   # TODO: synchronize better
    exec > /dev/tty 2>&1
}

preexec() {
    exec > >(tee ~/.command.out&)
}

Questo utilizza l' preexechook di zsh execcon cui eseguire teeper archiviare una copia dello stdout del comando, quindi usa precmdper leggere l'output memorizzato e ripristinare stdout in modo che sia solo il terminale per mostrare il prompt.

Ma ha ancora bisogno di un po 'di lavoro. Ad esempio, poiché stdout non è più un terminale, programmi come vime lessnon funzionano correttamente.

Ci sono alcune utili informazioni correlate in queste domande:


Sì, forse un approccio automatico al 100% non funzionerà. Ci sono molte execchiamate nel codice, il comando è in esecuzione più volte o sono bloccato in una semantica speciale?
unperson325680,

execsenza un nome di programma imposta solo i reindirizzamenti.
Mikel,

2

Puoi farlo semplicemente eseguendo il piping dei risultati tee, che salva l'output in un file e lo visualizza allo stesso tempo.

Quindi, ad esempio, potresti farlo, che mostra il tuo output come normale, ma lo salva anche nel file /tmp/it

locate foobar.mmpz | tee /tmp/it

quindi cat quel file e grep per selezionare cose, ad es

cat /tmp/it | grep progo | grep lms

quindi per usarlo, potresti semplicemente fare questo:

vi $(!!)


2

Mi è venuta in mente questa soluzione a metà cottura:

alias -g ___='"$(eval "$(fc -ln -1)" | tail -n 1)"'

Ciò consente di scrivere ___in qualsiasi punto della riga di comando. Il comando precedente verrà rieseguito e ___verrà sostituito con l'ultima riga del suo output. Esempio di utilizzo:

$ touch foo bar baz
$ ls -1
bar
baz
foo
$ vim ___

L'ultimo comando verrà espanso in vim foo.

Questo ha alcuni spigoli vivi!

  • Se si include ___un comando ma il comando precedente includeva anche a ___, la shell si bloccherà in uno stato strano per un po '. Puoi uscire da questo stato immediatamente con Ctrl- C.

  • Inoltre, non puoi premere Tabper espandere ___, come puoi fare con !$e altre costruzioni.

  • Alcuni comandi visualizzeranno output diversi quando vengono eseguiti “normalmente” e quando sono collegati a una pipe. (Confronta l'output di lse ls | cat.) Se il comando attivato da ___è uno di questi, potresti finire con un comando diverso da quello previsto.

  • E, naturalmente, se volessi fare qualcosa con una linea di uscita diversa dall'ultima, questo non ti aiuterà.

Ho scelto il nome ___perché è qualcosa che non avrei mai voluto includere come parola in una riga di comando, nemmeno come argomento. Potresti scegliere un nome diverso, ma fai attenzione a non scegliere qualcosa che potrebbe essere espanso per te inavvertitamente.

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.