Як усунути роздратування при запуску GUI з терміналу?


14

Я вважаю за краще запускати програми GUI з вікна терміналу, а не використовувати графічний робочий стіл. Часта роздратованість полягає в тому, що часто розробники не очікували такого типу використання, тому додаток друкує безліч непотрібних, криптовалютних або неінформативних повідомлень для stdout або stderr. Подальше скупчення терміналу виникає через те, що запуск програми у фоновому режимі з допомогою & генерує звіти про створення та припинення завдання.

Яке вирішення цих проблем може приймати аргументи командного рядка та обробляти автоматичне завершення?

Пов’язано: /programming/7131670/make-bash-alias-that-takes-parameter

Відповіді:


15

Негайне перенаправлення стандартної помилки на /dev/nullпогану ідею, оскільки вона приховує ранні повідомлення про помилки, а збої можуть бути важкими для діагностики. Я пропоную щось на зразок наступного start-appсценарію 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 &

Просто запустіть його: start-app your_command argument ...

Цей сценарій видасть не більше 10 рядків повідомлень і не більше 5 секунд. Однак зауважте, що якщо програма негайно виходить з ладу (наприклад, через помилку сегментації), ви не побачите жодного повідомлення про помилку. Звичайно, ви можете змінювати цей сценарій різними способами, щоб робити те, що ви хочете ...

Примітка. Щоб зробити завершення роботи з start-appzsh, достатньо зробити:

compdef _precommand start-app

і в басі:

complete -F _command start-app

(скопійовано з тієї, що входить до execта timeв /usr/share/bash-completion/bash_completion).


6
Мила ідея, +1. Але я не погоджуюся з тим, що в цілому погана ідея перенаправляти stderr з програми GUI. 99% всіх користувачів звернуться до нього з графічного робочого столу, тому вони ніколи не побачать нічого, що перейшло б на більш складний. Програмне забезпечення призначене для повідомлення про помилки через GUI. Що ви бачите на stdout та stderr, як правило, налагоджувальні повідомлення, які розробники не намагалися виймати, оскільки не думали, що їх хтось побачить.
Бен Кроуелл

@BenCrowell Я погоджуюся, що програми GUI повинні повідомляти про помилки через графічний інтерфейс, але в деяких випадках може трапитися помилка програми перед тим, як запустити графічний інтерфейс. Зокрема, це відбувається, коли додаток викликається скриптом для обгортки, який аналізує аргументи (загалом це не проблема для користувачів, які запускають додаток з робочого столу, оскільки в цьому випадку аргументи повинні бути правильними).
vinc17

@BenCrowell Я також думаю про випадок, коли $DISPLAYне встановлено (наприклад, якщо користувач забув -Xдля ssh) або проблему авторизації X, як тут: unix.stackexchange.com/questions/108679/…
vinc17

@mikeserv Я думаю, що це питання можуть зацікавити різних користувачів (не лише ОП), і вони можуть використовувати або bash, або zsh. Я щойно додав замітку про доповнення в zsh та bash. Як бачите, це просто.
vinc17

@mikeserv Зверніть увагу, що на дату є тест. Простіший і портативний, але менш гнучкий, якщо потрібно додати функції: "$@" 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 &(найважливішим моментом була ідея, а не реальна реалізація).
vinc17

5

Ця відповідь - за баш. Як приклад, ось що я роблю в своєму .bashrc, щоб зробити команду зручності, evщоб запустити переглядач PDF Evince.

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

Перший рядок визначає функцію ev. Ім'я функції буде розпізнано, коли ви використовуєте її в командному рядку, як це:

ev foo.pdf

(Це інший механізм, ніж псевдоніми, і має нижчий пріоритет.) Виведення Evince до stdin і stdout надсилається до бітбукета (/ dev / null). Амперсанд ставить завдання на другий план. Навколишня команда в круглих дужках змушує її запускати в підпакеті, щоб вона не друкувала повідомлення про створення фонового завдання або його завершення.

Другий рядок з мого .bashrc використовує повну функцію bash, щоб повідомити bash, що аргументом команди ev є файл з розширенням pdf. Це означає, що якщо у мене також є файли foo.tex, foo.aux і т. Д., Сидячи в моєму каталозі, я можу набрати ev fooі натиснути клавішу вкладки, і bash буде знати, щоб заповнити ім'я файлу як foo.pdf.


1
Бен, так що ти знаєш, що ти можеш трохи перестаратися з функцією. Жодне ображення не означало - це чудова відповідь, і я першим звернувся до питання про відповіді, але ... врахуйтеev() (evince "$@" >&2 &) 2>/dev/null
mikeserv

Абоev() (evince "$@" &>/dev/null $)
glenn jackman

@glenn: Я вважаю, що ви мали намір передостаннім персонажем у вашій пропозиції стати а &.
G-Man каже: "Відновіть Моніку"

Так, цілком правильно.
Гленн Джекман

5

Іншою можливістю є використання commandдля execдемонстрації від спеціального вбудованого до простого старого вбудованого типу:

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

Тож тепер ви можете:

(shh; call some process &)

Я щойно помітив, що commandце не працює zsh (як це здається в більшості інших оболонок) , але там, де він не працює, ви можете зробити замість цього:

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

... які повинні працювати всюди.

Насправді ви можете навіть зробити:

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

Отже, ви можете зробити:

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

ВИХІД

can anyone hear

Після обговорення коментаря з @ vinc17, варто відзначити, що майже весь вихід консолі програми GUI, як правило, призначений для Xtty - його консолі. Коли ви запускаєте Xдодаток з X .desktopфайлу, вихід, який він генерує, перенаправляється до Xвіртуального терміналу - що б там не було, з якого ви запустили Xв першу чергу. Я можу звернутися до цього номеру у Tty $XDG_VTNR.

Дивно, але, можливо, тому, що я тільки почав використовувати, startxя більше не можу, як просто писати /dev/tty$XDG_VTNR. Це також може (як я вважаю, що це більш імовірно) має щось Xorgспільне з самими останніми і різкими змінами, впровадженими з v1.16, що дозволяє йому запускатись під час systemdсеансу користувача, а не вимагати привілеїв root .

І все-таки я можу:

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

(gui; some x app &)

Тепер весь some x appвихід з консолі спрямовується до /dev/tty$((1+$XDG_VTNR))мого xtermpty. Я можу отримати останню сторінку цього в будь-який час, наприклад:

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

Це, мабуть, найкраща практика присвятити якомусь віртуальному терміналу для входу в журнал. /dev/consoleяк правило, вже зарезервовано для цього, хоча ви можете віддати перевагу не робити того, chownщо, ймовірно, потрібно, щоб мимоволі писати на це. Можливо, у вас є якась функція, яка дозволяє вам робити printk- що в основному друкується /dev/console- і тому могла б використовувати його так, як я думаю.

Інший спосіб зробити це було б присвятити PTY для таких цілей. Наприклад, ви можете тримати xtermвікно відкритим, зберігати висновок ttyпри запуску звідти в змінну середовища і використовувати це значення в якості місця призначення для guiвихідних даних. Таким чином усі журнали будуть перенесені в окреме вікно журналу, через яке ви зможете прокручувати, якщо вам це подобається.

Я колись написав відповідь про те, як подібне можна зробити з bashісторією, якщо ти зацікавився.


1
Я пропоную вам видалити своє зауваження щодо результатів, echo $?оскільки воно додає непотрібну інформацію, і воно базується на помилці в bash, про яку я недавно повідомляв тут: list.gnu.org/archive/html/bug-bash/2014- 08 / msg00081.html та в Debian BTS: bugs.debian.org/cgi-bin/bugreport.cgi?bug=758969
vinc17

@ vinc17 yup - я думаю, я повинен був зробити це в баші, що дивно - тому що я ніколи не використовую цю оболонку. здогадуюсь я тільки для цієї відповіді.
mikeserv
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.