Jak powstrzymać gedit (i inne programy) przed wysyłaniem ostrzeżeń GTK i tym podobnych w moim terminalu?

32

Korzystam z niesamowitego menedżera okien na zaufanym po aktualizacji z raring. Moje środowisko pulpitu celowo nie ma uruchomionych wszystkich demonów Gnome / Freedesktop - nie chcę ich.

Kiedy wykonuję geditz takiego terminalu:

gedit file

Wysyła takie komunikaty na całym terminalu za każdym razem, gdy nacisnę klawisz Enter, zapisz lub przy różnych innych okazjach:

(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

Rozumiem znaczenie tego ostrzeżenia i zdecydowałem, że nie ma to dla mnie znaczenia.

Jak mogę wyłączyć tego rodzaju ostrzeżenie? Przez „wyłącz” nie rozumiem żadnego z tych lub podobnych obejść:

  • przesyłanie danych wyjściowych programu gedit do /dev/null
  • napisanie skryptu opakowującego, który potokuje dane wyjściowe gedit /dev/null
  • tworzenie aliasu, w którym przesyłane są dane wyjściowe programu gedit /dev/null

Te obejścia są niedopuszczalne, ponieważ muszą być stosowane indywidualnie do każdej aplikacji Gnome - gedit nie jest jedynym, który lubi zepsuć terminal.

FUZxxl
źródło
2
Dlaczego nie możesz użyć 3 wspomnianych opcji?
Tim
Nie sądzę, że możesz wyłączyć te ostrzeżenia, ale jak zapytał @Tim, co masz przeciwko wykorzystaniu 3 opcji, które rozwiązałyby twój problem?
ElefantPhace
7
Dzięki, wiem jak zrobić przekierowanie powłoki. Powodem, dla którego nie chcę tego robić (i wyraźnie to stwierdzam), jest to, że te ostrzeżenia pojawiają się również w wielu innych programach. Opcja konfiguracji dbus lub dowolnego komponentu, który generuje te ostrzeżenia, wyłączy ostrzeżenie dla wszystkich programów, które je generują. Dzięki przekierowaniu muszę zastosować obejście (które nie jest rozwiązaniem) do każdego programu osobno.
FUZxxl,
@FUZxxl Nie mogę zmusić mojego programu gedit do spójnego wyświetlania błędów. Ale jestem ciekawy, czy export GCONF_DEBUG="no"zrobiłbym cokolwiek
Dan
@ dan08 Nie, nie rób tego.
FUZxxl,

Odpowiedzi:

17

Po pierwsze, denerwuje mnie również to, że te ostrzeżenia pojawiają się w gotowym systemie Ubuntu, bez żadnej „właściwej” metody ich wyłączenia, którą mógłbym znaleźć (wydaje się, że najczęstszym „rozwiązaniem” jest instalacja gir1.2-gtksource-3.0co wydaje się nie działać, ponieważ jest już zainstalowane lub je zignorować - ale chcę je całkowicie ukryć, ponieważ powodują one hałas w moim terminalu).

Wymyśliłem następujący kod, który do tej pory wydaje się zachowywać dokładnie tak, jak się tego spodziewałem i jest oparty na odpowiedzi TuKsn, ale nieco go ulepsza:

  • Pracuj domyślnie ( gedit ...) bez potrzeby używania F12 lub innego skrótu (aby wywołać niefiltrowane użycie /usr/bin/gedit ...).
  • Wyświetla wprowadzoną nazwę polecenia, gdy kończy się jako zadanie w tle.

Nadal można trochę uogólnić, ale na razie, jeśli potrzebujesz takiego samego traktowania dla innych poleceń, powiel gedit()funkcję dla każdej nazwy polecenia, która wymaga tego samego filtra.

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

I lepsza wersja (znacznie mniejsza, w pełni ogólna, nie ma potrzeby przepisywania historii, ponieważ jest wywoływana w obecnej postaci, i lepsza do filtrowania według wiersza niż całego wyniku):

# 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
źródło
To świetna odpowiedź. Użyję tego w przyszłości.
FUZxxl,
2

Jest to również obejście, ale nie musisz stosować tego do każdej aplikacji.

Napisz to do siebie .bashrci możesz użyć tego opakowania z klawiszem F12 (lub wybrać inny klucz), aby ukryć ostrzeżenia:

# 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
źródło
To wygląda nieco lepiej. Zamierzam to przetestować.
FUZxxl,
1

Właściwie napisałem narzędzie ukrywania ostrzeżeń w C, które jest o wiele łatwiejsze w użyciu niż skrypt pokazany powyżej. Będzie również napisać wszystkie dane wyjściowe do pisemnego stdoutdomyślnie (bo GTK i inne ostrzeżenia wysyłane są stderrtak analizuje stderrnie stdoutdomyślnie).

Jednym z dużych problemów z powyższym skryptem jest to, że nie napisze niczego na konsoli, nawet jeśli nie będzie pasować do wyrażenia regularnego, dopóki nie zostanie wykonane. Jest tak, ponieważ zapisuje wszystkie dane w zmiennej, a następnie grep tej zmiennej po zakończeniu. Oznacza to również, że zapisze dane wyjściowe w tej zmiennej, prawdopodobnie wykorzystując dużo pamięci (przynajmniej powinieneś zapisać to w pliku tymczasowym). Wreszcie, z tego co widzę, grep zapobiegnie wyświetleniu, jeśli jakakolwiek linia będzie pasować . Może nie dokładnie to, czego chcesz.

Narzędzia można użyć w prostym aliasie:

alias gvim="hide-warnings gvim"

(Używam gvim... jestem pewien, że to też zadziała gedit.)

Plik jest samowystarczalny, bez zależności innych niż biblioteka C, dzięki czemu można uzyskać kopię oraz łatwo skompilować i zainstalować:

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

Plik zawiera dodatkową dokumentację, której można użyć --helppo skompilowaniu do szybkich dokumentów.

Nowsza wersja , która w pewnym momencie będzie korzystać z biblioteki advgetopt, jest w C ++.

Alexis Wilke
źródło
Link jest martwy.
Armin Rigo,
@ArminRigo, Ah! Poruszyło się. Tutaj umieściłem nowy link do najnowszego przed przeniesieniem, ponieważ teraz jest to C ++. Jest też link do wersji C ++. Wersja C już się nie zmieni.
Alexis Wilke,
0

Sam szukałem narzędzia do rozwiązania tego rodzaju problemu.

Moje problemy z udzielonymi odpowiedziami są następujące:

  • ważne jest, aby stdout i stderr nie były agregowane w jeden strumień
  • Nie mogę wywołać polecenia, przefiltrować wszystkich danych wyjściowych, dopóki się nie skończy, i wydrukować na końcu (tzn. Rozwiązanie musi poprawnie przesyłać dane wyjściowe)
  • Chciałbym zachować jak najwięcej kolejności komunikatów stdout i stderr

Doceniam próby, które widziałem, aby to zrobić z Bash, jednak nie udało mi się znaleźć rozwiązania, które spełniło wszystkie 3 warunki opisane powyżej.

Moje najlepsze rozwiązanie zostało napisane w NodeJS, które, jak rozumiem, nie będzie instalowane na wielu urządzeniach z Linuksem. Zanim zdecydowałem się napisać wersję JS, próbowałem zakodować ją w Pythonie i odkryłem, że asynchroniczna biblioteka IO jest dość brzydka i zepsuta aż do BARDZO najnowszych wersji Pythona (~ 3.5, które jest dostępne gotowe w NIEKTÓRYCH nowszych dystrybucjach).

Minimalizowanie zależności było JEDYNYM powodem wyboru Pythona, więc porzuciłem go dla NodeJS, który ma niezwykły zestaw bibliotek dla nieco niższego poziomu, IO zorientowanego na asynchronię.

Oto on:

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

Aby użyć tego skryptu, możesz dodać następujące wiersze do pliku .bashrc:

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

Podproces, który wybierzesz do uruchomienia, odziedziczy stdin, więc możesz swobodnie korzystać z potoków BASH lub przekierowań.

Shane
źródło