使命令的输出出现在单行上[关闭]

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 是否适用于所有人,还是必须先安装? 也不适用于cpcp 没有抱怨,但它也没有做它应该做的事情。 Nether 做了前面的回答。 =[ @CJxD:我对此进行了测试。它绝对适用于我在 Ubuntu 上。您是否可能在不同的平台上,tar 将其输出发送到 stderr 而不是 stdout?在这种情况下,您需要在管道之前添加2&gt;&amp;1,将stderr 重定向到stdout,这样管道就会捕获它。 @CJxD:哦,我看到了您对其他答案的评论,即 tar 将所有内容都作为参数。你确定你的 tar 命令不只是有引用问题吗? Bash 解释命令行,用管道做自己的事情,并将参数提供给tartar 没有办法抓住管道,除非你逃避它,所以 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 没关系

以上是关于使命令的输出出现在单行上[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

在新行而不是单行上输出 json 对象组

Linux下如何对目录中的文件进行统计

Perl单行(Perl One-Liners)命令

Beautifulsoup - get_text,单行输出

关闭控制台中的广告输出/错误

如何在单行代码中删除 python 3 中类列表中的 [ , ] 和单引号? [关闭]