Comment empêcher gedit (et d'autres programmes) de générer des avertissements GTK et autres dans mon terminal?

32

J'exécute le gestionnaire de fenêtres génial sur trusty après avoir mis à niveau depuis raring. Mon environnement de bureau n'a pas intentionnellement tous les démons Gnome / Freedesktop en cours d'exécution - je n'en veux pas.

Lorsque j'exécute à geditpartir d'un terminal comme celui-ci:

gedit file

Il affiche des messages comme celui-ci partout sur mon terminal chaque fois que j'appuie sur Entrée ou Enregistrer ou à diverses autres occasions:

(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

Je comprends la signification de cet avertissement et j'ai décidé que cela n'avait pas d'importance pour moi.

Comment désactiver ce type d'avertissement? Par «désactiver», je ne veux dire aucune de ces solutions de contournement ou similaires:

  • canaliser la sortie de gedit dans /dev/null
  • écrire un script wrapper qui dirige la sortie de gedit dans /dev/null
  • création d'un alias qui dirige la sortie de gedit dans /dev/null

Ces solutions de contournement ne sont pas acceptables car elles doivent être appliquées individuellement à chaque application Gnome - gedit n'est pas le seul à aimer gâcher le terminal.

FUZxxl
la source
2
Pourquoi ne pouvez-vous pas utiliser les 3 options que vous avez mentionnées?
Tim
Je ne pense pas que vous puissiez désactiver ces avertissements, mais comme @Tim l'a demandé, qu'avez-vous contre l'utilisation des 3 options qui résoudraient votre problème?
ElefantPhace
7
Merci, je sais comment faire la redirection shell. La raison pour laquelle je ne veux pas faire cela (et le dire explicitement) est que ces avertissements apparaissent également dans de nombreux autres programmes. Une option de configuration pour dbus ou tout composant qui génère ces avertissements désactivera l'avertissement pour tous les programmes qui le génèrent. Avec la redirection, je dois appliquer la solution de contournement (qui n'est pas une solution) à chaque programme individuellement.
FUZxxl
@FUZxxl Je n'arrive pas à obtenir mon gedit pour générer des erreurs de manière cohérente. Mais je suis curieux de savoir si export GCONF_DEBUG="no"je ferais quelque chose
Dan
@ dan08 Non, je ne fais pas l'affaire.
FUZxxl

Réponses:

17

Tout d'abord, je trouve également ennuyeux que ces avertissements apparaissent sur un Ubuntu prêt à l'emploi, sans méthode "appropriée" pour les désactiver que je pourrais trouver (il semble que la "solution" la plus courante soit soit d'installer gir1.2-gtksource-3.0ce qui ne semble pas fonctionner car il est déjà installé, ou les ignorer - mais je veux les supprimer complètement car ils rendent mon terminal bruyant).

J'ai trouvé le code suivant qui jusqu'à présent semble se comporter exactement comme je m'y attendais, et est basé sur la réponse de TuKsn, mais l'améliore un peu pour:

  • Travaillez par défaut ( gedit ...) sans avoir besoin d'utiliser F12 ou un autre raccourci (pour invoquer une utilisation non filtrée /usr/bin/gedit ...).
  • Affiche le nom de commande entré lorsqu'il se termine en tâche de fond.

Peut encore être généralisé un peu, mais pour l'instant, si vous avez besoin du même traitement pour les autres commandes, dupliquez la gedit()fonction pour chaque autre nom de commande qui a besoin du même filtre.

# 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) $@
}

Et une meilleure version (beaucoup plus petite, entièrement générique, pas besoin de réécrire l'historique car invoquée telle quelle, et meilleure pour le filtrage par ligne plutôt que la sortie entière):

# 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
la source
C'est une excellente réponse. Je vais l'utiliser à l'avenir.
FUZxxl
2

C'est aussi une solution de contournement, mais vous n'avez pas à appliquer cela pour chaque application.

Écrivez ceci dans votre .bashrcet vous pouvez utiliser ce wrapper avec F12 (ou choisir une autre clé) pour supprimer les avertissements:

# 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
la source
Cela semble un peu mieux. Je vais tester ça.
FUZxxl
1

J'ai en fait écrit l' outil de masquage des avertissements en C que je trouve beaucoup plus facile à utiliser que le script illustré ci-dessus. En outre, il écrira toutes les sorties écrites stdoutpar défaut (car le Gtk et les autres avertissements sont envoyés à stderril stderrne les analyse pas stdoutpar défaut).

Un gros problème avec le script ci-dessus est qu'il n'écrira rien sur votre console, même s'il ne correspond pas à l'expression régulière, jusqu'à ce qu'il soit terminé. En effet, il enregistre toutes les données dans une variable, puis grep cette variable une fois terminé. Cela signifie également qu'il enregistrera la sortie dans cette variable en utilisant éventuellement beaucoup de mémoire (au moins, vous devriez l'enregistrer dans un fichier temporaire.) Enfin, d'après ce que je peux voir, le grep empêchera tout affichage si une ligne correspond . Peut-être pas exactement ce que vous voulez.

L'outil peut être utilisé dans un alias simple comme celui-ci:

alias gvim="hide-warnings gvim"

(J'utilise gvim... Je suis sûr que cela fonctionnerait geditaussi.)

Le fichier est autonome, aucune dépendance autre que la bibliothèque C, vous pouvez donc obtenir une copie et facilement la compiler et l'installer:

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

Il y a une documentation supplémentaire dans le fichier et vous pouvez l'utiliser --helpune fois compilé pour des documents rapides.

La nouvelle version , qui à un moment donné utilisera la bibliothèque advgetopt, est en C ++.

Alexis Wilke
la source
Le lien est mort.
Armin Rigo
@ArminRigo, Ah! Ça bouge. Ici, j'ai mis un nouveau lien vers le dernier avant qu'il ne bouge car maintenant c'est C ++. Il existe également un lien vers la version C ++. La version C ne changera plus.
Alexis Wilke
0

Je cherchais moi-même un utilitaire pour résoudre ce genre de problème.

Mes problèmes avec les réponses fournies sont les suivants:

  • il est important que stdout et stderr ne soient pas regroupés en un seul flux
  • Je ne peux pas appeler une commande, filtrer toute la sortie jusqu'à ce qu'elle se termine et l'imprimer à la fin (c'est-à-dire que la solution doit diffuser la sortie correctement)
  • Je souhaite conserver autant que possible l'ordre des messages stdout et stderr

J'apprécie les tentatives que j'ai vues pour faire cela avec Bash, cependant, je n'ai pas réussi à identifier une solution qui remplisse les 3 conditions décrites ci-dessus.

Ma solution ultime est écrite en NodeJS, qui, je crois, ne sera pas installée sur de nombreuses boîtes Linux. Avant de choisir d'écrire la version JS, j'ai essayé de la coder en python, et j'ai trouvé que la bibliothèque asynchrone d'E / S était assez moche et cassée jusqu'à des versions TRÈS récentes de python (~ 3.5 qui est disponible dès le départ sur certaines distributions plus récentes).

Minimiser les dépendances était la SEULE raison de choisir python, donc je l'ai abandonné pour NodeJS, qui possède un ensemble remarquable de bibliothèques pour des E / S asynchrones quelque peu bas niveau.

C'est ici:

#!/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))

Pour utiliser ce script, vous pouvez ajouter ces lignes à votre .bashrc:

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

Le sous-processus que vous choisissez d'exécuter héritera de stdin, vous êtes donc libre d'utiliser les canaux BASH ou la redirection.

Shane
la source