Ben*_*ell 14 bash autocomplete
我更喜欢从终端窗口启动 GUI 应用程序,而不是使用图形桌面。一个常见的烦恼是,开发人员通常没有预料到这种类型的使用,因此应用程序会向 stdout 或 stderr 打印大量无用、神秘或无信息的消息。终端上会出现进一步的混乱,因为在后台运行程序,使用 & 会生成有关创建和终止作业的报告。
对于这些接受命令行参数并处理自动完成的问题,有什么解决方法?
相关:https : //stackoverflow.com/questions/7131670/make-bash-alias-that-takes-parameter
vin*_*c17 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 &
Run Code Online (Sandbox Code Playgroud)
只需运行它: start-app your_command argument ...
此脚本最多输出 10 行消息,最多输出 5 秒。但是请注意,如果应用程序立即崩溃(例如,由于分段错误),您将看不到任何错误消息。当然,你可以通过各种方式修改这个脚本来做你想做的......
注意:要start-app在 zsh 中使用补全,只需执行以下操作:
compdef _precommand start-app
Run Code Online (Sandbox Code Playgroud)
在 bash 中:
complete -F _command start-app
Run Code Online (Sandbox Code Playgroud)
(复制自 forexec和timein /usr/share/bash-completion/bash_completion)。
这个答案是针对 bash 的。例如,这是我在 .bashrc 中执行的操作,以创建ev启动 PDF 查看器 Evince的便捷命令。
ev() { (evince "$1" 1>/dev/null 2>/dev/null &) }
complete -f -o default -X '!*.pdf' ev
Run Code Online (Sandbox Code Playgroud)
第一行定义了一个函数ev。当您像这样在命令行上使用函数时,函数的名称将被识别:
ev foo.pdf
Run Code Online (Sandbox Code Playgroud)
(这是与别名不同的机制,并且具有较低的优先级。)Evince 到 stdin 和 stdout 的输出被发送到 bitbucket (/dev/null)。&符号将作业置于后台。将命令括在括号中会使其在子 shell 中运行,因此它不会打印有关后台作业创建或其完成的消息。
我的 .bashrc 中的第二行使用 bash 的完整函数来告诉 bash ev 命令的参数应该是一个扩展名为 pdf 的文件。这意味着,如果我的目录中还有文件 foo.tex、foo.aux 等,我可以键入ev foo并点击 Tab 键,bash 将知道将文件名补全为 foo.pdf。
另一种可能性是使用command降级exec从一个特殊的内置于一个普通的旧内建这样的:
alias shh='command exec >/dev/null 2>&1'
Run Code Online (Sandbox Code Playgroud)
所以现在你可以这样做:
(shh; call some process &)
Run Code Online (Sandbox Code Playgroud)
我刚刚注意到它command不起作用zsh (就像在大多数其他外壳中一样),但是在它不起作用的地方你可以做:
alias shh='eval "exec >/dev/null 2>&1"'
Run Code Online (Sandbox Code Playgroud)
...这应该适用于任何地方。
事实上,你甚至可以这样做:
alias shh='command exec >"${O:-/dev/null}" 2>&1'
Run Code Online (Sandbox Code Playgroud)
所以你可以这样做:
O=./logfile; (shh;echo can anyone hear &)
O=; (shh; echo this\? &)
cat ./logfile
Run Code Online (Sandbox Code Playgroud)
can anyone hear
Run Code Online (Sandbox Code Playgroud)
跟进@vinc17 的评论讨论,值得注意的是,几乎所有 GUI 应用程序的控制台输出通常都用于X's tty - 它的控制台。当您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 &)
Run Code Online (Sandbox Code Playgroud)
现在所有some x app的控制台输出都被路由到/dev/tty$((1+$XDG_VTNR))而不是 myxterm的 pty。我可以随时获取此内容的最后一页,例如:
fmt </dev/vcs$((1+$XDG_VTNR))
Run Code Online (Sandbox Code Playgroud)
无论如何,将一些虚拟终端专用于记录输出可能是最佳实践。/dev/console通常已经为此保留,尽管您可能不希望这样做chown可能需要您愉快地写信。你可能有一些功能可以让你做一个printk- 这基本上是打印到/dev/console- 所以我想可以这样使用它。
另一种方法是将pty专用于此类目的。例如,您可以xterm打开一个窗口,将tty运行时的输出保存在环境变量中,并将该值用作gui的输出目标。通过这种方式,所有日志都将被路由到一个单独的日志窗口,然后您可以根据需要滚动浏览。
如果您有兴趣,我曾经写过一篇关于如何用bash历史完成类似事情的答案。