我更喜欢从终端窗口启动 GUI 应用程序,而不是使用图形桌面。一个常见的烦恼是,开发人员通常没有预料到这种类型的使用,因此应用程序会向 stdout 或 stderr 打印大量无用、神秘或无信息的消息。由于使用 & 在后台运行程序,会生成作业创建和终止的报告,因此终端上会出现进一步的混乱。
对于这些问题,接受命令行参数并处理自动完成的解决方法是什么?
有关的:https://stackoverflow.com/questions/7131670/make-bash-alias-that-takes-parameter
答案1
立即将标准错误重定向到/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 秒。但请注意,如果应用程序立即崩溃(例如由于分段错误),您将不会看到任何错误消息。当然,您可以通过各种方式修改此脚本来执行您想要的操作......
注意:要在 zsh 中使用补全功能start-app
,只需执行以下操作:
compdef _precommand start-app
在bash中:
complete -F _command start-app
(从 forexec
和time
in中复制/usr/share/bash-completion/bash_completion
)。
答案2
这个答案是针对 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 的完整函数来告诉 bash ev 命令的参数应该是一个扩展名为 pdf 的文件。这意味着,如果我的目录中还有文件 foo.tex、foo.aux 等,我可以键入ev foo
并按 Tab 键,bash 就会知道将文件名补全为 foo.pdf。
答案3
另一种可能性是使用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 应用程序的控制台输出通常都是用于X
s tty - 它的控制台。当您X
从X
.desktop
文件运行应用程序时,它生成的输出将路由到X
的虚拟终端 - 这是您X
最初启动的任何 tty。我可以用 来寻址这个 tty 号码$XDG_VTNR
。
但奇怪的是 - 也许是因为我刚刚开始使用startx
- 我似乎不能再只写到/dev/tty$XDG_VTNR
.这也可能(我认为可能性更大)与 v1.16中最近实现的重大更改有关,Xorg
该更改允许它在用户会话下运行,systemd
而不是要求根特权。
不过,我可以这样做:
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
- 所以我想可以这样使用它。
做到这一点的另一种方法是专门普蒂达到这样的目的。例如,您可以保持一个xterm
窗口打开,将运行时的输出保存在环境变量中,并使用该值作为的输出的tty
目标。gui
这样,所有日志都会被路由到一个单独的日志窗口,然后您可以根据需要滚动浏览。
我曾经写过一个答案bash
如果您感兴趣的话,可以了解如何对历史做类似的事情。