Jak wyeliminować uciążliwości podczas uruchamiania GUI z terminala?

14

Wolę uruchamiać aplikacje GUI z okna terminala niż przy użyciu pulpitu graficznego. Częstą irytacją jest to, że często programiści nie przewidywali tego rodzaju użycia, więc aplikacja drukuje wiele niepotrzebnych, tajemniczych lub nieinformacyjnych wiadomości na stdout lub stderr. Występuje dalszy bałagan na terminalu, ponieważ uruchomienie programu w tle, z &, generuje raporty o utworzeniu i zakończeniu zadania.

Jakie jest obejście tych problemów, które będą akceptować argumenty wiersza poleceń i obsługiwać automatyczne uzupełnianie?

Powiązane: /programming/7131670/make-bash-alias-that-takes-parameter

Ben Crowell
źródło

Odpowiedzi:

15

Natychmiastowe przekierowanie standardowego błędu /dev/nulljest złym pomysłem, ponieważ ukryje wczesne komunikaty o błędach, a awarie mogą być trudne do diagnozowania. Sugeruję coś takiego jak następujący start-appskrypt 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 &

Po prostu uruchom go z: start-app your_command argument ...

Skrypt wyświetli maksymalnie 10 wierszy wiadomości i maksymalnie 5 sekund. Pamiętaj jednak, że jeśli aplikacja natychmiast się zawiesi (np. Z powodu błędu segmentacji), nie zobaczysz żadnego komunikatu o błędzie. Oczywiście możesz modyfikować ten skrypt na różne sposoby, aby robić to, co chcesz ...

Uwaga: Aby uzupełnienia działały start-appw programie zsh, wystarczy:

compdef _precommand start-app

i bash:

complete -F _command start-app

(skopiowane z jednego do execi timew /usr/share/bash-completion/bash_completion).

vinc17
źródło
6
Fajny pomysł, +1. Ale nie zgadzam się, że przekierowywanie stderr z aplikacji GUI jest ogólnie złym pomysłem. 99% wszystkich użytkowników wywoła go z graficznego pulpitu, więc nigdy nie zobaczyliby niczego, co trafiłoby do stderr. Oprogramowanie zostało zaprojektowane do zgłaszania błędów za pomocą GUI. To, co widzisz na stdout i stderr, to zwykle debugowanie wiadomości, których programiści nie zadawali sobie trudu, ponieważ nie sądzili, że ktoś je zobaczy.
Ben Crowell,
@BenCrowell Zgadzam się, że aplikacje GUI powinny zgłaszać błędy za pośrednictwem GUI, ale w niektórych przypadkach może się zdarzyć, że aplikacja ulegnie awarii przed uruchomieniem GUI. Dzieje się tak w szczególności, gdy aplikacja jest wywoływana za pomocą skryptu opakowującego, który analizuje argumenty (ogólnie nie jest to problem dla użytkowników, którzy uruchamiają aplikację z pulpitu, ponieważ w tym przypadku argumenty powinny być poprawne).
vinc17
@BenCrowell Myślę również o przypadku, gdy $DISPLAYnie jest ustawiony (np. Jeśli użytkownik zapomniał -Xo ssh) lub problem z autoryzacją X, taki jak tutaj: unix.stackexchange.com/questions/108679/...
vinc17 18.08.18
@mikeserv Myślę, że różni użytkownicy mogą być zainteresowani tym pytaniem (nie tylko OP) i mogą używać albo bash, albo zsh. Właśnie dodałem notatkę o ukończeniu w Zsh i Bash. Jak widać, jest to proste.
vinc17
@mikeserv Pamiętaj, że w tym dniu jest test. Prostsze i bardziej przenośne, ale mniej elastyczne, jeśli chce się dodać funkcje: "$@" 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 &(najważniejszym punktem był pomysł, a nie faktyczna implementacja).
vinc17
5

Ta odpowiedź jest na bash. Jako przykład, oto co robię w moim .bashrc, aby wykonać polecenie wygody, evaby uruchomić przeglądarkę plików PDF Evince.

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

Pierwszy wiersz definiuje funkcję ev. Nazwa funkcji zostanie rozpoznana, gdy użyjesz jej w wierszu poleceń w następujący sposób:

ev foo.pdf

(Jest to inny mechanizm niż aliasy i ma niższy priorytet.) Dane wyjściowe Evince'a do stdin i stdout są wysyłane do bitbucket (/ dev / null). Znak ampersand umieszcza zadanie w tle. Otaczanie polecenia w nawiasach powoduje, że jest ono uruchamiane w podpowłoce, aby nie drukowało komunikatów o utworzeniu zadania w tle lub jego zakończeniu.

Druga linia z mojego .bashrc używa pełnej funkcji bash, aby powiedzieć bashowi, że argumentem polecenia ev powinien być plik z rozszerzeniem pdf. Oznacza to, że jeśli mam również pliki foo.tex, foo.aux itp., Które siedzą w moim katalogu, mogę pisać ev fooi naciskać klawisz Tab, a bash będzie wiedział, że należy uzupełnić nazwę pliku jako foo.pdf.

Ben Crowell
źródło
1
Ben, żebyś wiedział, że możesz przesadzić z tą funkcją. Bez obrazy oznaczało - to świetna odpowiedź i byłem pierwszym, który głosował za pytaniami i odpowiedziami, ale ... rozważev() (evince "$@" >&2 &) 2>/dev/null
mikeserv
Lubev() (evince "$@" &>/dev/null $)
glenn jackman
@glenn: Uważam, że chciałeś, aby przedostatnia postać w twojej sugestii była &.
G-Man mówi „Przywróć Monikę”
Tak, całkiem dobrze.
glenn jackman
5

Inną możliwością jest commandobniżenie wersji execze specjalnego wbudowanego do zwykłego starego wbudowanego, takiego jak:

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

Teraz możesz zrobić:

(shh; call some process &)

Właśnie zauważyłem, że commandto nie działa zsh (jak to wygląda w większości innych powłok) , ale tam, gdzie to nie działa, możesz zamiast tego:

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

... które powinny działać wszędzie.

W rzeczywistości możesz nawet:

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

Więc możesz zrobić:

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

WYNIK

can anyone hear

Po dyskusji na komentarzu z @ vinc17, warto zauważyć, że prawie wszystkie dane wyjściowe konsoli GUI są generalnie przeznaczone dla Xtty - konsoli. Po uruchomieniu Xaplikacji z X .desktoppliku generowane przez nią dane wyjściowe są kierowane do Xwirtualnego terminala - czyli tego, co to było, z którego uruchomiłeś Xaplikację. Mogę zaadresować ten numer tty za pomocą $XDG_VTNR.

O dziwo - i może dlatego, że właśnie zacząłem używać startx- nie mogę już pisać /dev/tty$XDG_VTNR. Może to również (jak sądzę jest bardziej prawdopodobne) mieć coś wspólnego z ostatnią i drastyczną zmianą zaimplementowaną w wersji Xorg1.16, która pozwala mu działać w systemdsesji użytkownika, zamiast wymagać uprawnień roota .

Nadal mogę:

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

(gui; some x app &)

Teraz wszystkie some x appwyjścia konsoli są kierowane /dev/tty$((1+$XDG_VTNR))raczej do mojego xtermpty. W każdej chwili mogę uzyskać ostatnią stronę tego:

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

Prawdopodobnie najlepszą praktyką jest dedykowanie terminalu wirtualnego do rejestrowania danych wyjściowych. /dev/consolejest na ogół już zarezerwowany do tego, choć możesz nie chcieć robić tego, chownco jest prawdopodobnie wymagane, abyś beztrosko pisał na ten temat. Możesz mieć jakąś funkcję, która pozwala ci zrobić printk- co w zasadzie drukuje /dev/console- i dlatego możesz użyć tego w ten sposób.

Innym sposobem na zrobienie tego byłoby poświęcenie pieniędzy na takie cele. Możesz na przykład pozostawić xtermotwarte okno, zapisać dane wyjściowe ttypo uruchomieniu z niego w zmiennej środowiskowej i użyć tej wartości jako miejsca docelowego dla guidanych wyjściowych. W ten sposób wszystkie dzienniki zostaną przekierowane do osobnego okna dziennika, które możesz następnie przewinąć, jeśli chcesz.

Kiedyś napisałem odpowiedź o tym, jak podobną rzecz można zrobić z bashhistorią, jeśli jesteś zainteresowany.

mikeserv
źródło
1
Sugeruję, abyś usunął uwagę na wyjściu, echo $?ponieważ dodaje ona niepotrzebne informacje i jest oparty na błędzie w bash, który właśnie zgłosiłem tutaj: lists.gnu.org/archive/html/bug-bash/2014- 08 / msg00081.html oraz w BTS Debiana: bugs.debian.org/cgi-bin/bugreport.cgi?bug=758969
vinc17
@ vinc17 tak - myślę, że musiałem to zrobić w bash, co jest dziwne - ponieważ nigdy nie używam tej powłoki. chyba tylko dla tej odpowiedzi.
mikeserv