Come eliminare i fastidi all'avvio di una GUI da un terminale?


14

Preferisco avviare le applicazioni della GUI da una finestra del terminale piuttosto che usando un desktop grafico. Un fastidio frequente è che spesso gli sviluppatori non hanno previsto questo tipo di utilizzo, quindi l'app stampa molti messaggi inutili, criptici o non informativi su stdout o stderr. Un ulteriore disordine sul terminale si verifica perché l'esecuzione del programma in background, con un &, genera rapporti sulla creazione e la conclusione del lavoro.

Che cosa è una soluzione alternativa per questi problemi che accettano argomenti della riga di comando e gestiscono il completamento automatico?

Correlati: /programming/7131670/make-bash-alias-that-takes-parameter

Risposte:


15

Reindirizzare immediatamente l'errore standard a /dev/nullè una cattiva idea in quanto nasconderà i primi messaggi di errore e gli errori potrebbero essere difficili da diagnosticare. Suggerisco qualcosa come il seguente start-appscript zsh:

#!/usr/bin/env zsh
coproc "$@" 2>&1
quit=$(($(date +%s)+5))
nlines=0
while [[ $((nlines++)) -lt 10 ]] && read -p -t 5 line
do
  [[ $(date +%s) -ge $quit ]] && break
  printf "[%s] %s\n" "$(date +%T)" "$line"
done &

Basta eseguirlo con: start-app your_command argument ...

Questo script genererà al massimo 10 righe di messaggi e per un massimo di 5 secondi. Si noti tuttavia che se l'applicazione si blocca immediatamente (ad esempio a causa di un errore di segmentazione), non verrà visualizzato alcun messaggio di errore. Ovviamente, puoi modificare questo script in vari modi per fare quello che vuoi ...

Nota: per far funzionare i completamenti con start-appin zsh, è sufficiente:

compdef _precommand start-app

e in bash:

complete -F _command start-app

(copiato da quello per exece timein /usr/share/bash-completion/bash_completion).


6
Idea carina, +1. Ma non sono d'accordo sul fatto che sia una cattiva idea in generale reindirizzare stderr da un'app GUI. Il 99% di tutti gli utenti lo invocherà da un desktop grafico, quindi non vedrebbero mai nulla che sia andato su stderr. Il software è progettato per segnalare errori tramite la GUI. Quello che vedi su stdout e stderr è in genere il debug dei messaggi che gli sviluppatori non si sono preoccupati di eliminare perché non pensavano che qualcuno li avrebbe visti.
Ben Crowell,

@BenCrowell Sono d'accordo che le app della GUI debbano segnalare errori tramite la GUI, ma in alcuni casi può accadere che l'applicazione non riesca prima di avviare la GUI. Ciò si verifica in particolare quando l'applicazione viene invocata tramite uno script wrapper che analizza gli argomenti (in generale, questo non è un problema per gli utenti che avviano l'app dal desktop poiché in questo caso gli argomenti dovrebbero essere corretti).
vinc17,

@BenCrowell Penso anche al caso in cui $DISPLAYnon è impostato (ad esempio se l'utente ha dimenticato a -Xper ssh) o un problema di autorizzazione X come qui: unix.stackexchange.com/questions/108679/…
vinc17

@mikeserv Penso che vari utenti potrebbero essere interessati a questa domanda (non solo all'OP) e possono usare bash o zsh. Ho appena aggiunto una nota per i completamenti in zsh e bash. Come puoi vedere, questo è semplice.
vinc17,

@mikeserv Nota che c'è un test alla data. Più semplice e più portatile, ma meno flessibile se si desidera aggiungere funzionalità: "$@" 2>&1 | { quit=$(($(date +%s)+5)); while read line && [ $(date +%s) -lt $quit ]; do printf "[%s] %s\n" "$(date +%T)" "$line"; done; } | head -n 10 &(il punto più importante era l'idea, non l'implementazione effettiva).
vinc17,

5

Questa risposta è per bash. Ad esempio, ecco cosa faccio nel mio .bashrc per eseguire un comando pratico evper avviare il visualizzatore PDF Evince.

ev() { (evince "$1" 1>/dev/null 2>/dev/null &) }
complete -f -o default -X '!*.pdf' ev

La prima riga definisce una funzione ev. Il nome di una funzione verrà riconosciuto quando lo si utilizza dalla riga di comando in questo modo:

ev foo.pdf

(Questo è un meccanismo diverso dagli alias e ha una priorità inferiore.) L'output di Evince su stdin e stdout viene inviato al bitbucket (/ dev / null). La e commerciale mette il lavoro in secondo piano. Il comando racchiuso tra parentesi fa sì che venga eseguito in una subshell in modo che non stampi messaggi sulla creazione del lavoro in background o sul suo completamento.

La seconda riga del mio .bashrc usa la funzione completa di bash per dire a bash che l'argomento del comando ev dovrebbe essere un file con l'estensione pdf. Questo significa che se ho anche i file foo.tex, foo.aux, ecc., Nella mia directory, posso digitare ev fooe premere il tasto Tab e Bash saprà completare il nome del file come foo.pdf.


1
Ben, solo per sapere che potresti esagerare un po 'con la funzione. Nessuna offesa significava: è un'ottima risposta e sono stato il primo a votare domande e risposte, ma ... consideraev() (evince "$@" >&2 &) 2>/dev/null
mikeserv il

Oppureev() (evince "$@" &>/dev/null $)
glenn jackman,

@glenn: Credo che tu abbia voluto che il penultimo personaggio nel tuo suggerimento fosse un &.
G-Man dice "Ripristina Monica" il

Sì, giusto.
Glenn Jackman,

5

Un'altra possibilità è quella di usare commandper passare execda un builtin speciale ad un semplice vecchio build come:

alias shh='command exec >/dev/null 2>&1'

Quindi ora puoi fare:

(shh; call some process &)

Ho appena notato che commandnon funziona zsh (come sembra fare nella maggior parte delle altre shell) , ma dove invece non funziona puoi invece fare:

alias shh='eval "exec >/dev/null 2>&1"'

... che dovrebbe funzionare ovunque.

In effetti, potresti persino fare:

alias shh='command exec >"${O:-/dev/null}" 2>&1'

Quindi potresti fare:

O=./logfile; (shh;echo can anyone hear &)
O=; (shh; echo this\? &)
cat ./logfile

PRODUZIONE

can anyone hear

Dopo una discussione di commento con @ vinc17, vale la pena notare che quasi tutto l'output della console di un'app GUI è generalmente destinato a Xtty - la sua console. Quando esegui Xun'app da un X .desktopfile, l'output che genera viene instradato al Xterminale virtuale, che è qualunque sia il tty da cui è stato lanciato Xin primo luogo. Posso indirizzare questo numero tty con $XDG_VTNR.

Stranamente però - e forse perché ho appena iniziato a usare startx- non riesco più a scrivere /dev/tty$XDG_VTNR. Questo potrebbe anche (come penso sia più probabile) avere qualcosa a che fare con il cambiamento molto recente e drastico implementato con Xorgv1.16 che gli consente di funzionare in una systemdsessione utente piuttosto che richiedere i privilegi di root .

Tuttavia, posso fare:

alias gui='command exec >/dev/tty$((1+$XDG_VTNR)) 2>&1'

(gui; some x app &)

Ora tutto l' some x appoutput della console viene instradato /dev/tty$((1+$XDG_VTNR))piuttosto che il mio xtermpty. Posso ottenere l'ultima pagina di questo in qualsiasi momento come:

fmt </dev/vcs$((1+$XDG_VTNR))

Probabilmente è buona prassi dedicare comunque un terminale virtuale per registrare l'output. /dev/consoleè generalmente già riservato per questo, anche se potresti preferire di non fare chownciò che è probabilmente necessario per poterti scrivere allegramente. Potresti avere una funzione che ti consente di fare un printk- che sostanzialmente sta stampando su /dev/console- e quindi potrei usarlo in questo modo suppongo.

Un altro modo per farlo sarebbe quello di dedicare un po ' a tali scopi. Ad esempio, è possibile mantenere xtermaperta una finestra, salvare l'output di ttyquando eseguito da lì in una variabile di ambiente e utilizzare quel valore come destinazione per guil'output di. In questo modo tutti i registri verrebbero instradati verso una finestra di registro separata, che è quindi possibile scorrere se desiderato.

Una volta ho scritto una risposta su come una cosa simile potrebbe essere fatta con la bashstoria, se ti interessa.


1
Ti suggerisco di rimuovere la tua osservazione sull'output di echo $?in quanto aggiunge informazioni inutili e si basa su un bug in bash, che ho appena riportato qui: lists.gnu.org/archive/html/bug-bash/2014- 08 / msg00081.html e nel Debian BTS: bugs.debian.org/cgi-bin/bugreport.cgi?bug=758969
vinc17

@ vinc17 yup - credo di averlo fatto in bash che è strano - perché non uso mai quella shell. Immagino solo per questa risposta.
Mikeserv,
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.