Wie verhindere ich, dass gedit (und andere Programme) GTK-Warnungen und ähnliches in meinem Terminal ausgibt?

32

Nachdem ich von raring aufgerüstet habe, starte ich den fantastischen Fenstermanager auf Trusty. In meiner Desktop-Umgebung werden absichtlich nicht alle Gnome / Freedesktop-Dämonen ausgeführt - ich möchte sie nicht.

Wenn ich geditvon einem Terminal wie diesem ausführe :

gedit file

Es gibt Nachrichten wie diese überall auf meinem Terminal aus, wenn ich die Eingabetaste drücke, speichere oder bei verschiedenen anderen Gelegenheiten:

(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

Ich verstehe die Bedeutung dieser Warnung und habe entschieden, dass es mir egal ist.

Wie kann ich diese Art von Warnung ausschalten ? Mit "Ausschalten" meine ich keine der folgenden oder ähnlichen Problemumgehungen:

  • Leiten der Ausgabe von gedit in /dev/null
  • Schreiben eines Wrapper-Skripts, in das die Ausgabe von gedit geleitet wird /dev/null
  • Erstellen eines Alias, in den die Ausgabe von gedit geleitet wird /dev/null

Diese Problemumgehungen sind nicht akzeptabel, da sie für jede Gnome-Anwendung einzeln angewendet werden müssen - gedit ist nicht die einzige, die das Terminal durcheinander bringen möchte.

FUZxxl
quelle
2
Warum können Sie die drei genannten Optionen nicht verwenden?
Tim
Ich glaube nicht, dass Sie diese Warnungen deaktivieren können, aber wie @Tim gefragt hat, was haben Sie dagegen, die drei Optionen zu verwenden, die Ihr Problem lösen würden?
ElefantPhace
7
Danke, ich weiß, wie man eine Shell-Umleitung macht. Der Grund, warum ich dies nicht tun möchte (und ausdrücklich darauf hinweise), ist, dass diese Warnungen auch in vielen anderen Programmen erscheinen. Eine Konfigurationsoption für dbus oder eine andere Komponente, die diese Warnungen generiert, deaktiviert die Warnung für alle Programme, die diese Warnungen generieren. Bei der Umleitung muss ich die Problemumgehung (die keine Lösung ist) für jedes Programm einzeln anwenden.
FUZxxl
@FUZxxl Ich kann mein gedit nicht dazu bringen, Fehler konsistent auszugeben. Aber ich bin neugierig, ob export GCONF_DEBUG="no"ich irgendetwas tun würde
Dan
@ dan08 Nein, mach den Trick nicht.
FUZxxl

Antworten:

17

Erstens finde ich es auch ärgerlich, dass diese Warnungen auf einem Standard-Ubuntu angezeigt werden und keine "richtige" Methode zum Deaktivieren vorhanden ist, die ich finden könnte (anscheinend ist die häufigste "Lösung" entweder die Installation gir1.2-gtksource-3.0das scheint nicht zu funktionieren, da es bereits installiert ist, oder sie zu ignorieren - aber ich möchte sie vollständig unterdrücken, da sie mein Terminal nur laut machen.

Ich habe den folgenden Code gefunden, der sich bisher genau so zu verhalten scheint, wie ich es erwartet hätte. Er basiert auf der Antwort von TuKsn, verbessert ihn jedoch ein wenig:

  • Arbeiten Sie standardmäßig ( gedit ...), ohne F12 oder eine andere Verknüpfung verwenden zu müssen (um die ungefilterte Verwendung aufzurufen /usr/bin/gedit ...).
  • Zeigt den eingegebenen Befehlsnamen an, wenn er als Hintergrundaufgabe beendet wird.

Kann noch ein bisschen verallgemeinert werden, aber wenn Sie für andere Befehle die gleiche Behandlung benötigen, duplizieren Sie die gedit()Funktion für jeden anderen Befehlsnamen, der denselben Filter benötigt.

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

Und eine bessere Version (viel kleiner, voll generisch, keine Notwendigkeit, den Verlauf neu zu schreiben, seitdem er aufgerufen wurde, und besser zum Filtern pro Zeile als für die gesamte Ausgabe):

# 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
quelle
Das ist eine großartige Antwort. Ich werde das in Zukunft nutzen.
FUZxxl,
2

Es ist auch eine Problemumgehung, aber Sie müssen dies nicht für jede Anwendung anwenden.

Schreiben Sie dies in Ihr .bashrcund Sie können diesen Wrapper mit F12 (oder einer anderen Taste) verwenden, um die Warnungen zu unterdrücken:

# 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
quelle
Das sieht etwas besser aus. Ich werde das testen.
FUZxxl
1

Ich habe das Tool zum Ausblenden von Warnungen in C geschrieben, das für mich viel einfacher zu verwenden ist als das oben gezeigte Skript. Außerdem werden alle Ausgaben geschrieben, in die stdoutstandardmäßig geschrieben wurde (da die Gtk- und andere Warnungen an gesendet werden, stderrsodass sie stderrnicht stdoutstandardmäßig analysiert werden).

Ein großes Problem mit dem obigen Skript ist, dass es nichts auf Ihre Konsole schreibt, auch wenn es nicht mit dem regulären Ausdruck übereinstimmt, bis es fertig ist. Dies liegt daran, dass alle Daten in einer Variablen gespeichert werden und diese Variable anschließend überprüft wird. Dies bedeutet auch, dass die Ausgabe in dieser Variablen gespeichert wird, möglicherweise unter Verwendung von viel Speicher (zumindest sollten Sie dies in einer temporären Datei speichern.) Schließlich verhindert das grep, wie ich sehe, jede Anzeige, wenn eine Zeile übereinstimmt . Vielleicht nicht genau das, was du willst.

Das Tool kann in einem einfachen Alias ​​wie folgt verwendet werden:

alias gvim="hide-warnings gvim"

(Ich benutze gvim... ich bin sicher, es würde auch funktionieren gedit.)

Die Datei ist in sich geschlossen, keine anderen Abhängigkeiten als die C-Bibliothek, sodass Sie eine Kopie erhalten und diese einfach kompilieren und installieren können:

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

Die Datei enthält einige weitere Dokumentationen, die Sie --helpnach dem Kompilieren für Schnelldokumentationen verwenden können.

Die neuere Version , die irgendwann die advgetopt-Bibliothek verwenden wird, ist in C ++.

Alexis Wilke
quelle
Der Link ist tot.
Armin Rigo
@ArminRigo, Ah! Es bewegte sich. Hier habe ich einen neuen Link zu dem neuesten eingefügt, bevor es verschoben wurde, da es jetzt C ++ ist. Es gibt auch einen Link zur C ++ - Version. Die C-Version wird sich nicht mehr ändern.
Alexis Wilke
0

Ich war auf der Suche nach einem Dienstprogramm, um diese Art von Problem selbst zu lösen.

Meine Probleme mit den bereitgestellten Antworten lauten wie folgt:

  • Es ist wichtig, dass stdout und stderr nicht zu einem Stream zusammengefasst werden
  • Ich kann keinen Befehl aufrufen, die gesamte Ausgabe filtern, bis sie beendet ist, und am Ende ausdrucken (dh die Lösung muss die Ausgabe ordnungsgemäß streamen).
  • Ich möchte die Reihenfolge der Nachrichten stdout und stderr so weit wie möglich beibehalten

Ich schätze die Versuche, die ich gesehen habe, um dies mit Bash zu tun, aber ich konnte keine Lösung identifizieren, die alle drei oben beschriebenen Bedingungen erfüllte.

Meine ultimative Lösung ist in NodeJS geschrieben, was meines Wissens nicht auf vielen Linux-Boxen installiert werden kann. Bevor ich mich entschied, die JS-Version zu schreiben, habe ich versucht, sie in Python zu codieren, und festgestellt, dass die asynchrone E / A-Bibliothek ziemlich hässlich und kaputt ist, bis SEHR aktuelle Versionen von Python (~ 3.5, die in EINIGEN neueren Distributionen sofort verfügbar sind).

Das Minimieren von Abhängigkeiten war der EINZIGE Grund, warum ich mich für Python entschieden habe. Deshalb habe ich es für NodeJS aufgegeben, das eine bemerkenswerte Sammlung von Bibliotheken für asynchrone E / A-Vorgänge auf niedriger Ebene enthält.

Hier ist es:

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

Um dieses Skript zu verwenden, können Sie Ihrer .bashrc-Datei die folgenden Zeilen hinzufügen:

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

Der Subprozess, den Sie ausführen, übernimmt stdin, sodass Sie BASH-Pipes oder Umleitungen verwenden können.

Shane
quelle