使命令的输出出现在单行上[关闭]
Posted
技术标签:
【中文标题】使命令的输出出现在单行上[关闭]【英文标题】:Make output of command appear on single line [closed] 【发布时间】:2012-02-03 14:33:15 【问题描述】:是否可以获取命令的输出(例如tar
)以将每一行输出仅写入一行?
示例用法:
tar -options -f dest source | [insert trickery here]
并且输出将显示正在处理的每个文件,而不会使屏幕移动:每个输出都会覆盖最后一个。能做到吗?
编辑:我们似乎有一个可行的答案,但让我们更进一步: 做同样的事情,但超过 5 行怎么样?您会看到不影响终端其余部分的滚动输出。我想我已经有了答案,但我想看看你们的想法。
【问题讨论】:
【参考方案1】:用回车替换换行符。
tar -options -f dest source | cut -b1-$(tput cols) | sed -u 'i\\o033[2K' | stdbuf -o0 tr '\n' '\r'; echo
解释:
cut -b1-$(tput cols)
:如果 tar 的输出长于终端宽度,则截断它的输出。根据您希望终端移动的程度,这不是绝对必要的。
sed -u 'i\\o033[2K'
:在每行的开头插入一行空白。 sed 的 -u
选项将其置于无缓冲模式。 stdbuf -oL sed 'i\\033[2K'
也同样有效。
stdbuf -o0 tr '\n' '\r'
:使用tr
与回车交换换行符。 Stdbuf 确保输出是无缓冲的;如果没有\n
,在行缓冲终端上,我们将看不到任何输出。
echo
:输出最后一个换行符,这样终端提示符就不会吃掉最后一行。
对于您的编辑提出的问题:
x=0;
echo -e '\e[s';
tar -options -f dest source | while read line; do
echo -en "\e[u"
if [ $x gt 0 ]; then echo -en "\e["$x"B"; fi;
echo -en "\e[2K"
echo -n $line | cut -b1-$(tput cols);
let "x = ($x+1)%5";
done; echo;
您可以随意将所有内容集中到一行上。这实际上为原始问题产生了另一种解决方案:
echo -e '\e[s'; tar -options -f dest source | while read line; do echo -en "\e[u\e2K"; echo -n $line | cut -b1-$(tput cols); done; echo
它完全依赖于 VT100 代码。
【讨论】:
或者用回车,导致下一行被覆盖:tr '\012' '\015'
我想你想在最后打印一个换行符,这样当它完成时就不会搞砸你的提示。
我认为这根本不是 OP 想要的。他想要某种控制字符的诡计(使用退格键或其他东西),以便将输出全部写入同一个位置。
我不知道为什么每个人都赞成这个;它不起作用,因为标准输出没有被刷新。
@Dave,很好用sed
,但我觉得应该是| cut -b1-$(tput cols) | sed -u 'i\\o033[2K' | tr '\n' '\r'; echo
,用cut来修剪过宽的线条。【参考方案2】:
感谢 Dave/tripleee 的核心机制(用回车替换换行符),这是一个实际工作的版本:
tar [opts] [args] | perl -e '$| = 1; while (<>) s/\n/\r/; print; print "\n"'
设置$|
会导致perl 在每个print
之后自动刷新,而不是等待换行符,并且尾随换行符使您的最后一行输出不会在命令完成并且bash 打印提示时被(部分)覆盖。 (如果它是部分的,那真的很难看,提示符和光标后跟输出行的其余部分。)
使用tr
完成此操作会很好,但我不知道如何强制tr
(或任何类似标准)刷新标准输出。
编辑:以前的版本实际上很难看,因为它没有清除 after 行的其余部分输出了什么。这意味着较长行后面的较短行有剩余的尾随文本。这(诚然丑陋)解决了这个问题:
tar [opts] [args] | perl -e '$| = 1; $f = "%-" . `tput cols` . "s\r"; $f =~ s/\n//; while (<>) s/\n//; printf $f, $_; print "\n"'
(您还可以通过更多 perl-y 方式获取终端宽度,as described here;不过我不想依赖 CPAN 模块。
【讨论】:
也不喜欢这种方法。无论出于何种原因,管道都被忽略了。另外,Perl 是否适用于所有人,还是必须先安装? 也不适用于cp
。 cp
没有抱怨,但它也没有做它应该做的事情。 Nether 做了前面的回答。 =[
@CJxD:我对此进行了测试。它绝对适用于我在 Ubuntu 上。您是否可能在不同的平台上,tar
将其输出发送到 stderr 而不是 stdout?在这种情况下,您需要在管道之前添加2>&1
,将stderr 重定向到stdout,这样管道就会捕获它。
@CJxD:哦,我看到了您对其他答案的评论,即 tar 将所有内容都作为参数。你确定你的 tar 命令不只是有引用问题吗? Bash 解释命令行,用管道做自己的事情,并将参数提供给tar
; tar
没有办法抓住管道,除非你逃避它,所以 bash 没有赋予它特殊的意义。我使用这个命令进行了测试:tar xvf foo.tar.gz | perl ...
@jefromi:我认为这听起来比将正常输出发送到标准错误的平台更有可能......【参考方案3】:
tar -options -f dest source | cut -b1-$(tput cols) | perl -ne 's/^/\e[2K/; s/\n/\r/; print' ;echo
解释:
| cut -b1-$(tput cols)
这是为了确保列不会太宽。
(在 perl -ne 中)s/^/\e[2K/
此代码清除当前行,擦除“旧”行。这应该在行的开头,以确保保留最后一行输出,并确保在下一行可用之前我们不会删除一行。
(In perl -ne) s/\n/\r/
tr
命令当然可以在这里使用。但是一旦我开始使用 perl,我就坚持下去了
PS 澄清一下:有两个不同的“线宽”问题。两者都必须解决。 (1)我们需要清除线路,这样短的线路就不会与旧的、较长的线路混在一起。 (2) 如果一条线很长,并且比当前终端宽度宽,那么我们需要修剪它。
【讨论】:
如果在行尾,就没有输出;它打印的每一行都会立即擦除 @Dave,我已经更新了一些工作。可以吗:开始是为了“..确保在下一行可用之前我们不会删除一行。” @AaronMcDaid 没关系以上是关于使命令的输出出现在单行上[关闭]的主要内容,如果未能解决你的问题,请参考以下文章