从终端启动GUI时如何消除烦恼?


14

我更喜欢从终端窗口而不是使用图形桌面启动GUI应用程序。一个常见的烦恼是,开发人员常常没有预料到这种类型的使用,因此该应用程序会向stdout或stderr打印许多无用,含糊或无用的消息。由于在后台运行带有&的程序,会在终端上进一步造成混乱,从而生成作业创建和终止的报告。

这些将接受命令行参数并处理自动完成的问题的解决方法是什么?

相关:https : //stackoverflow.com/questions/7131670/make-bash-alias-that-takes-parameter

Answers:


15

立即将标准错误重定向到/dev/null是一个坏主意,因为它将隐藏早期的错误消息,并且故障可能很难诊断。我建议类似以下start-appzsh脚本的内容:

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

(从一个用于复制exectime/usr/share/bash-completion/bash_completion)。


6
可爱的主意,+ 1。但是我不同意从GUI应用程序重定向stderr通常是一个坏主意。99%的用户将从图形桌面调用它,因此他们永远不会看到任何传递给stderr的东西。该软件旨在通过GUI报告错误。您在stdout和stderr上看到的通常是调试消息,这些消息使开发人员不必费心取出,因为他们认为没有人会看到它们。
Ben Crowell 2014年

@BenCrowell我同意GUI应用程序应该通过GUI报告错误,但是在某些情况下,可能会发生应用程序启动GUI之前失败的情况。这种情况尤其发生在通过解析参数的包装脚本调用应用程序时(通常,对于从桌面启动应用程序的用户来说这不是问题,因为在这种情况下,参数应该是正确的)。
vinc17 2014年

@BenCrowell我也觉得这里的情况$DISPLAY没有设置(例如,如果用户忘记了一-X对SSH)或X授权问题喜欢这里:unix.stackexchange.com/questions/108679/...
vinc17

@mikeserv我认为各种用户可能对此问题感兴趣(而不仅仅是OP),他们可能使用bash或zsh。我刚刚在zsh和bash中添加了完成注释。如您所见,这很简单。
vinc17 2014年

@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

这个答案是针对bash的。举例来说,这是我在.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的消息发送到bitbucket(/ dev / null)。“&”号将作业置于后台。将命令括在括号中会导致它在子shell中运行,因此它不会显示有关后台作业的创建或完成的消息。

我的.bashrc的第二行使用bash的complete函数告诉bash,ev命令的参数应该是扩展名为pdf的文件。这意味着,如果我的目录中也有文件foo.tex,foo.aux等,则可以键入ev foo并按Tab键,bash会知道以foo.pdf格式完成文件名。


1
Ben,您知道,您可能在功能上有些过分了。没有冒犯的意思-这是一个很好的答案,我是第一个ev() (evince "$@" >&2 &) 2>/dev/null
反对问答

ev() (evince "$@" &>/dev/null $)
格伦·杰克曼

@glenn:我相信您在建议中将倒数第二个字符表示为&
G-Man说'Resstate Monica'2014年

是的,非常正确。
格伦·杰克曼

5

另一种可能性是使用command降级exec特殊的内置降级到普通的旧内置,例如:

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

现在,您可以执行以下操作:

(shh; call some process &)

我刚刚注意到,command它不能在其中工作zsh (就像在其他大多数shell中一样),但是在不工作的地方,您可以改为:

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应用程序的控制台输出通常都用于tty- X其控制台。XX .desktop文件运行应用程序时,其生成的输出将路由到X的虚拟终端-首先是从哪个tty启动X。我可以使用来解决这个tty号码$XDG_VTNR

奇怪的是-也许是因为我刚刚开始使用startx-我似乎再也无法写信给了/dev/tty$XDG_VTNR。这也可能(我认为更可能)Xorgv1.16 实施的最新变化有关,该变化允许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))而不是我xterm的pty。我可以随时获得该页面的最后一页,例如:

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

无论如何,最好是专用一些虚拟终端来记录输出。/dev/console通常已经为此预留了空间,尽管您可能不希望这样做,chown这可能会导致您愉快地写入该内容。您可能具有一些使您能够执行printk-基本上是打印到/dev/console-的功能,因此可以按照我想的方式使用它。

另一种方式做,这将是一个奉献PTY这样的目的。例如,您可以xterm打开一个窗口,tty将从那里运行时的输出保存在一个环境变量中,然后将该值用作gui输出的目标。这样,所有日志都将被路由到单独的日志窗口,然后您可以根据需要滚动浏览。

如果您感兴趣,我曾经写过一篇关于如何用bash历史完成类似事情的答案


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 2014年

@ vinc17是的-我想我一定是在bash中这样做的,这很奇怪-因为我从不使用该shell。猜猜我只是为了这个答案。
mikeserv
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.