Como eliminar aborrecimentos ao iniciar uma GUI a partir de um terminal?

14

Prefiro iniciar aplicativos GUI a partir de uma janela do terminal, em vez de usar uma área de trabalho gráfica. Um aborrecimento frequente é que, muitas vezes, os desenvolvedores não antecipam esse tipo de uso; portanto, o aplicativo imprime muitas mensagens inúteis, enigmáticas ou pouco informativas para stdout ou stderr. Mais confusão no terminal ocorre porque a execução do programa em segundo plano, com um &, gera relatórios da criação e finalização do trabalho.

Qual é uma solução alternativa para esses problemas que aceitam argumentos de linha de comando e manipulam o preenchimento automático?

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

Ben Crowell
fonte

Respostas:

15

Redirecionar o erro padrão imediatamente para /dev/nullé uma péssima idéia, pois oculta as mensagens de erro anteriores e pode ser difícil diagnosticar falhas. Sugiro algo como o seguinte 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 executá-lo com: start-app your_command argument ...

Este script produzirá no máximo 10 linhas de mensagens e no máximo 5 segundos. Observe, no entanto, que se o aplicativo travar imediatamente (por exemplo, devido a uma falha de segmentação), você não verá nenhuma mensagem de erro. Obviamente, você pode modificar esse script de várias maneiras para fazer o que deseja ...

Nota: Para que as conclusões funcionem start-appno zsh, basta:

compdef _precommand start-app

e no bash:

complete -F _command start-app

(copiado daquele exece timeentrando /usr/share/bash-completion/bash_completion).

vinc17
fonte
6
Ideia fofa, +1. Mas eu discordo que, em geral, é uma má idéia redirecionar o stderr a partir de um aplicativo GUI. 99% de todos os usuários irão invocá-lo em uma área de trabalho gráfica, para que nunca vejam nada que vá ao stderr. O software foi projetado para relatar erros através da GUI. O que você vê no stdout e no stderr é geralmente a depuração de mensagens que os desenvolvedores não se deram ao trabalho de remover porque não achavam que alguém as veria.
quer
@BenCrowell Concordo que os aplicativos da GUI devem relatar erros por meio da GUI, mas em alguns casos, pode acontecer que o aplicativo falhe antes de iniciar a GUI. Isso ocorre principalmente quando o aplicativo é chamado por meio de um script de wrapper que analisa os argumentos (em geral, isso não é um problema para usuários que iniciam o aplicativo a partir da área de trabalho, pois, nesse caso, os argumentos devem estar corretos).
precisa saber é
@BenCrowell Eu também penso no caso em que $DISPLAYnão está definido (por exemplo, se o usuário esqueceu um -Xpara ssh) ou um problema de autorização X como aqui: unix.stackexchange.com/questions/108679/…
vinc17
@ MikeServ Eu acho que vários usuários podem estar interessados ​​nesta questão (não apenas no OP), e eles podem usar o bash ou o zsh. Acabei de adicionar uma observação para conclusões no zsh e no bash. Como você pode ver, isso é simples.
precisa saber é
@ mikeserv Observe que há um teste na data. Mais simples e portátil, mas menos flexível, se você quiser adicionar recursos: "$@" 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 &(o ponto mais importante foi a ideia, não a implementação real).
precisa saber é
5

Esta resposta é para bash. Como exemplo, eis o que eu faço no meu .bashrc para fazer um comando de conveniência evpara iniciar o visualizador de PDF Evince.

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

A primeira linha define uma função ev. O nome de uma função será reconhecido quando você a usar na linha de comando desta maneira:

ev foo.pdf

(Este é um mecanismo diferente dos aliases e tem prioridade mais baixa.) A saída do Evince para stdin e stdout é enviada para o bitbucket (/ dev / null). Oe comercial coloca o trabalho em segundo plano. Colocar o comando entre parênteses faz com que ele seja executado em um subshell, para que não imprima mensagens sobre a criação do trabalho em segundo plano ou sua conclusão.

A segunda linha do meu .bashrc usa a função completa do bash para informar ao bash que se espera que o argumento do comando ev seja um arquivo com a extensão pdf. Isso significa que, se eu também tiver os arquivos foo.tex, foo.aux, etc., no meu diretório, posso digitar ev fooe pressionar a tecla tab, e o bash saberá concluir o nome do arquivo como foo.pdf.

Ben Crowell
fonte
1
Ben, só para você saber, você pode estar exagerando um pouco na função. Sem ofensa significava - é uma grande resposta e eu era o primeiro a upvote q & a, mas ... considerarev() (evince "$@" >&2 &) 2>/dev/null
mikeserv
Ouev() (evince "$@" &>/dev/null $)
glenn jackman
@glenn: Acredito que você quisesse que o penúltimo personagem em sua sugestão fosse a &.
G-Man diz 'Restabelecer Monica'
Sim, está certo.
Glenn Jackman
5

Outra possibilidade é usar commandpara rebaixar execde um embutido especial para um embutido antigo simples como:

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

Então agora você pode fazer:

(shh; call some process &)

Acabei de perceber que commandisso não funciona zsh (como parece acontecer na maioria das outras conchas) , mas onde não funciona, você pode:

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

... o que deve funcionar em qualquer lugar.

De fato, você pode até fazer:

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

Então você poderia fazer:

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

RESULTADO

can anyone hear

Após uma discussão de comentários com o @ vinc17, vale a pena notar que quase toda a saída do console de um aplicativo GUI geralmente se destina ao Xstyty - seu console. Quando você executa um Xaplicativo a partir de um X .desktoparquivo, a saída gerada é roteada para Xo terminal virtual - que é o tty de onde você iniciou X. Eu posso endereçar esse número tty com $XDG_VTNR.

Estranhamente - e talvez porque eu comecei a usar startx- não consigo mais escrever /dev/tty$XDG_VTNR. Isso também pode (como eu acho mais provável) ter algo a ver com as mudanças drásticas e recentes recentes implementadas na Xorgv1.16, que permitem que ela seja executada em uma systemdsessão de usuário em vez de exigir privilégios de root .

Ainda assim, eu posso fazer:

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

(gui; some x app &)

Agora, toda some x appa saída do console está sendo encaminhada para o pty /dev/tty$((1+$XDG_VTNR))do meu xterm. Posso obter a última página disso a qualquer momento, como:

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

Provavelmente, é uma boa prática dedicar algum terminal virtual para registrar a saída de qualquer maneira. /dev/consolegeralmente já está reservado para isso, embora você possa preferir não fazer o chownque é provavelmente necessário para que você possa escrever alegremente. Você pode ter alguma função que permite fazer printk- o que é basicamente imprimir /dev/console- e, portanto, poderia usá-lo dessa maneira, suponho.

Outra maneira de fazer isso seria dedicar um pty a esses propósitos. Você pode, por exemplo, manter uma xtermjanela aberta, salvar a saída ttyquando executada a partir daí em uma variável de ambiente e usar esse valor como destino da guisaída da. Dessa forma, todos os logs seriam roteados para uma janela de log separada, que você poderia percorrer se quisesse.

Certa vez, escrevi uma resposta sobre como algo semelhante poderia ser feito com a bashhistória, se você estiver interessado.

mikeserv
fonte
1
Sugiro que você remova seu comentário sobre a saída, echo $?pois ele adiciona informações inúteis e se baseia em um bug no bash, que acabei de relatar aqui: lists.gnu.org/archive/html/bug-bash/2014- 08 / msg00081.html e no Debian BTS: bugs.debian.org/cgi-bin/bugreport.cgi?bug=758969
vinc17
@ vinc17 yup - acho que devo ter feito isso no bash, o que é estranho - porque nunca uso esse shell. acho que eu apenas para esta resposta.
precisa saber é o seguinte