Como impedir o gedit (e outros programas) de emitir avisos GTK e similares no meu terminal?

32

Estou executando o gerenciador de janelas incrível em confiável depois de ter atualizado de raring. Meu ambiente de área de trabalho intencionalmente não possui todos os daemons Gnome / Freedesktop em execução - não os quero.

Quando executo geditde um terminal como este:

gedit file

Ele envia mensagens como esta em todo o meu terminal sempre que eu pressiono enter ou save ou em várias outras ocasiões:

(gedit:5700): Gtk-WARNING **: Calling Inhibit failed: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.SessionManager was not provided by any .service files

Entendo o significado deste aviso e decidi que não importa para mim.

Como posso desativar esse tipo de aviso? Ao "desativar", não quero dizer nenhuma dessas soluções alternativas ou similares:

  • canalizando a saída do gedit para /dev/null
  • escrevendo um script wrapper que canaliza a saída do gedit para /dev/null
  • criando um alias que canaliza a saída do gedit para /dev/null

Essas soluções alternativas não são aceitáveis, pois precisam ser aplicadas individualmente a cada aplicativo Gnome - o gedit não é o único que gosta de atrapalhar o terminal.

FUZxxl
fonte
2
Por que você não pode usar as três opções mencionadas?
Tim
Acho que você não pode desativar esses avisos, mas, como o @Tim perguntou, o que você tem contra o uso das três opções que resolveriam o seu problema?
precisa saber é o seguinte
7
Obrigado, eu sei como fazer o redirecionamento de shell. A razão pela qual eu não quero fazer isso (e declarar explicitamente isso) é que esses avisos também aparecem em muitos outros programas. Uma opção de configuração para o dbus ou qualquer componente que gere esses avisos desativará o aviso para todos os programas que o geram. Com o redirecionamento, tenho que aplicar a solução alternativa (que não é uma solução) para cada programa individualmente.
FUZxxl
@FUZxxl Não consigo fazer com que o meu gedit produza erros de forma consistente. Mas estou curioso para saber se export GCONF_DEBUG="no"faria alguma coisa
Dan
@ dan08 Não, não estou conseguindo.
FUZxxl

Respostas:

17

Primeiro, também acho irritante que esses avisos apareçam em um Ubuntu pronto para uso, sem um método "adequado" para desativá-los que eu possa encontrar (parece que a "solução" mais comum é instalar gir1.2-gtksource-3.0que parece não funcionar desde que já está instalado ou para ignorá-los - mas quero suprimi-los completamente, pois eles fazem meu terminal barulhento).

Eu vim com o seguinte código, que até agora parece se comportar exatamente como eu esperaria, e é baseado na resposta de TuKsn, mas aprimora um pouco para:

  • Trabalhe por padrão ( gedit ...) sem precisar usar F12 ou outro atalho (para chamar o uso não filtrado /usr/bin/gedit ...).
  • Exibe o nome do comando digitado quando ele termina como uma tarefa em segundo plano.

Ainda pode ser um pouco generalizado, mas, por enquanto, se você precisar do mesmo tratamento para outros comandos, duplique a gedit()função para o outro nome de comando que precisa do mesmo filtro.

# solution adapted from: http://askubuntu.com/questions/505594
# TODO: use a list of warnings instead of cramming all of them to a single grep.
# TODO: generalize gedit() to allow the same treatment for several commands
#       without duplicating the function with only a different name
# output filter. takes: name_for_history some_command [arguments]
# the first argument is required both for history, but also when invoking to bg
# such that it shows Done <name> ... instead of e.g. Done /usr/bin/gedit ...
suppress-gnome-warnings() {
    # $1 is the name which should appear on history but is otherwise unused.
    historyName=$1
    shift

    if [ -n "$*" ]; then
        # write the real command to history without the prefix
        # syntax adapted from http://stackoverflow.com/questions/4827690
        history -s "$historyName ${@:2}"

        # catch the command output
        errorMsg=$( $* 2>&1 )

        # check if the command output contains not a (one of two) GTK-Warnings
        if ! $(echo $errorMsg | grep -q 'Gtk-WARNING\|connect to accessibility bus'); then
            echo $errorMsg
        fi
    fi
}
gedit() {
  suppress-gnome-warnings $FUNCNAME $(which $FUNCNAME) $@
}

E uma versão melhor (muito menor, totalmente genérica, não é necessário reescrever o histórico desde que foi invocado, e é melhor para filtrar por linha, em vez de toda a saída):

# generates a function named $1 which:
# - executes $(which $1) [with args]
# - suppresses output lines which match $2
# e.g. adding: _supress echo "hello\|world"
# will generate this function:
# echo() { $(which echo) "$@" 2>&1 | tr -d '\r' | grep -v "hello\|world"; }
# and from now on, using echo will work normally except that lines with
# hello or world will not show at the output
# to see the generated functions, replace eval with echo below
# the 'tr' filter makes sure no spurious empty lines pass from some commands
_supress() {
  eval "$1() { \$(which $1) \"\$@\" 2>&1 | tr -d '\r' | grep -v \"$2\"; }"
}

_supress gedit          "Gtk-WARNING\|connect to accessibility bus"
_supress gnome-terminal "accessibility bus\|stop working with a future version"
_supress firefox        "g_slice_set_config"
avih
fonte
Esta é uma ótima resposta. Vou usar isso no futuro.
FUZxxl
2

Também é uma solução alternativa, mas você não precisa aplicá-lo a todos os aplicativos.

Escreva para o seu .bashrce você pode usar este wrapper com F12 (ou escolheu outra chave) para suprimir os avisos:

# output filter
of() { 
    if [ -n "$*" ]; then   
        # write the real command to history without the prefix "of" 
        history -s "$*"

        # catch the command output
        errorMsg=$( $* 2>&1 )

        # check if the command output contains not a GTK-Warning
        if ! $(echo $errorMsg | grep -q 'Gtk-WARNING'); then
            echo $errorMsg 
        fi
    fi
}

# write the function "of" before every command if the user presses F12
bind '"\e[24~": "\e[1~ of \e[4~\n"'
TuKsn
fonte
Parece um pouco melhor. Eu vou testar isso.
FUZxxl
1

Na verdade, eu escrevi a ferramenta hide-warnings em C, que acho muito mais fácil de usar do que o script mostrado acima. Além disso, ele gravará toda a saída gravada stdoutpor padrão (porque o Gtk e outros avisos são enviados para, stderrportanto, ele stderrnão analisa stdoutpor padrão).

Um grande problema com o script acima é que ele não gravará nada no seu console, mesmo que não corresponda ao regex, até terminar. Isso ocorre porque ele salva todos os dados em uma variável e, em seguida, faz o grep dessa variável. Isso também significa que ele salvará a saída nessa variável, possivelmente usando muita memória (pelo menos você deve salvá-la em um arquivo temporário). Finalmente, pelo que posso ver, o grep impedirá qualquer exibição se alguma linha corresponder . Talvez não seja exatamente o que você deseja.

A ferramenta pode ser usada em um alias simples como este:

alias gvim="hide-warnings gvim"

(Eu uso gvim... tenho certeza que funcionaria gedittambém.)

O arquivo é independente, sem dependências além da biblioteca C, para que você possa obter uma cópia, compilar e instalar facilmente:

gcc hide-warnings.c -o hide-warnings
sudo cp hide-warnings /usr/bin/.

Há alguma documentação adicional no arquivo e você pode usar --helpuma vez compilado para documentos rápidos.

A versão mais recente , que em algum momento fará uso da biblioteca advgetopt, está em C ++.

Alexis Wilke
fonte
O link está morto.
Armin Rigo
@ArminRigo, Ah! Mexeu-se. Aqui eu coloquei um novo link para o mais recente antes que ele se movesse, porque agora é C ++. Há também um link para a versão C ++. A versão C não mudará mais.
Alexis Wilke
0

Eu estava procurando por um utilitário para resolver esse tipo de problema, eu mesmo.

Meus problemas com as respostas fornecidas são os seguintes:

  • é importante que stdout e stderr não sejam agregados em um fluxo
  • Não consigo invocar um comando, filtrar toda a saída até que ela termine e imprimi-la no final (ou seja, a solução deve transmitir a saída corretamente)
  • Gostaria de preservar a ordem das mensagens stdout e stderr o máximo possível

Agradeço as tentativas que já vi de fazer isso com o Bash, mas não consegui identificar uma solução que atendesse todas as três condições descritas acima.

Minha solução definitiva está escrita no NodeJS, que eu entendo que não será instalado em muitas caixas Linux. Antes de optar por escrever a versão JS, tentei codificá-la em python e descobri que a biblioteca de E / S assíncrona é bastante feia e está quebrada até MUITAS versões recentes do python (~ 3.5, que está disponível em algumas distribuições mais recentes).

Minimizar as dependências foi o ÚNICO motivo para escolher o python, então eu o abandonei no NodeJS, que possui um conjunto notável de bibliotecas para E / S orientada a assíncrona de baixo nível.

Aqui está:

#!/usr/bin/env nodejs

const spawn = require('child_process').spawn

function usage() {
    console.warn('Usage: filter-err <error regex> <cmd> [<cmd arg> ...]')
    process.exit(1)
}

function main(err_regex, cmd_arr) {
    let filter = new RegExp(err_regex)

    let proc = spawn(cmd_arr[0], cmd_arr.slice(1), {
        shell: true,
        stdio: ['inherit', 'inherit', 'pipe']
    })

    proc.stderr.on('data', (err) => {
        err = err.toString('utf8')

        if (! err.match(filter))
            process.stderr.write(err)
    })

    proc.on('close', (code) => process.exit(code))
}

const argv = process.argv

if (argv.length < 4)
    usage()
else
    main(argv[2], argv.slice(3))

Para usar esse script, você pode adicionar essas linhas ao seu .bashrc:

alias gimp='filter-err "GLib-[^ ]*-WARNING" gimp'

O subprocesso que você escolher executar herdará o stdin, portanto, você poderá usar os tubos ou o redirecionamento BASH.

Shane
fonte