Как устранить неудобства при запуске графического интерфейса пользователя из терминала?

14

Я предпочитаю запускать приложения с графическим интерфейсом из окна терминала, а не с помощью графического рабочего стола. Часто раздражает то, что разработчики часто не ожидали такого использования, поэтому приложение выводит на 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-appв zsh, достаточно:

compdef _precommand start-app

и в bash:

complete -F _command start-app

(скопировано с одного для execи timeв /usr/share/bash-completion/bash_completion).

vinc17
источник
6
Симпатичная идея, +1. Но я не согласен с тем, что вообще плохая идея перенаправлять stderr из приложения с графическим интерфейсом. 99% всех пользователей будут вызывать его с графического рабочего стола, поэтому они никогда не увидят ничего, что пошло бы на stderr. Программное обеспечение предназначено для сообщения об ошибках через графический интерфейс. То, что вы видите на stdout и stderr, - это, как правило, отладка сообщений, которые разработчики не удосужились вынести, потому что они не думали, что кто-то их увидит.
Бен Кроуэлл
@BenCrowell Я согласен, что приложения с графическим интерфейсом должны сообщать об ошибках через графический интерфейс, но в некоторых случаях может произойти сбой приложения, прежде чем он запустит графический интерфейс. Это происходит, в частности, когда приложение вызывается через скрипт-обертку, который анализирует аргументы (как правило, это не проблема для пользователей, которые запускают приложение с рабочего стола, поскольку в этом случае аргументы должны быть правильными).
vinc17
@BenCrowell Я также думаю о случае, когда $DISPLAYне задано (например, если пользователь забыл a -Xдля ssh) или о проблеме авторизации X, как здесь: unix.stackexchange.com/questions/108679/…
vinc17
@mikeserv Я думаю, что этот вопрос может заинтересовать различных пользователей (не только OP), и они могут использовать 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и нажать клавишу Tab, и bash узнает, что имя файла должно заканчиваться как foo.pdf.

Бен Кроуэлл
источник
1
Бен, просто чтобы ты знал, ты, возможно, немного переусердствовал с этой функцией. Не обидеть означает - это отличный ответ, и я был первым, кто проголосовал за вопросы, но ... подумайтеev() (evince "$@" >&2 &) 2>/dev/null
mikeserv
Илиev() (evince "$@" &>/dev/null $)
Гленн Джекман
@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. Это также может (как мне кажется, более вероятно) иметь какое-то отношение к самым последним и радикальным изменениям, реализованным в Xorgv1.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историей, если вам интересно.

mikeserv
источник
1
Я предлагаю вам удалить свое замечание по выводу, echo $?поскольку оно добавляет бесполезную информацию, и оно основано на ошибке в bash, о которой я только что сообщил здесь: lists.gnu.org/archive/html/bug-bash/2014- 08 / msg00081.html и в Debian BTS: bugs.debian.org/cgi-bin/bugreport.cgi?bug=758969
vinc17
@ vinc17 Да, наверное, я сделал это в bash, что странно, потому что я никогда не использую эту оболочку. думаю, я просто за этот ответ.
mikeserv