【问题标题】:Displaying only single most recent line of a command's output仅显示命令输出的最近一行
【发布时间】:2017-02-16 19:42:41
【问题描述】:

如何在一行中打印类似rm -rv * 的命令输出?我认为它需要\r,但我不知道怎么做。

我需要这样的东西:

发件人:

removed /path/file1
removed /path/file2
removed /path/file3

收件人:Line 1 : removed /path/file1

然后:Line 1 : removed /path/file2

然后:Line 1 : removed /path/file3

编辑:我可能被误解了,我想让整个过程在同一行打印,随着命令输出另一行而改变(如removed /path/file123

EDIT2 :输出有时太长而无法在线显示(非常长的路径)。我也需要考虑这个问题的东西:
/very/very/very/long/path/to/a/very/very/very/far/file/with-a-very-very-very-long-name1
/very/very/very/long/path/to/a/very/very/very/far/file/with-a-very-very-very-long-name2
/very/very/very/long/path/to/a/very/very/very/far/file/with-a-very-very-very-long-name3

【问题讨论】:

  • 你能提供一个示例输入和所需的输出吗?
  • 您希望每个文件名都删除前一个文件名,所有文件名都显示在命令运行的同一行。对吗?
  • @JohnKugelman 是的!

标签: bash terminal output


【解决方案1】:

这是一个辅助函数:

shopt -s checkwinsize # ensure that COLUMNS is available w/ window size

oneline() {
  local ws
  while IFS= read -r line; do
    if (( ${#line} >= COLUMNS )); then
      # Moving cursor back to the front of the line so user input doesn't force wrapping
      printf '\r%s\r' "${line:0:$COLUMNS}"
    else
      ws=$(( COLUMNS - ${#line} ))
      # by writing each line twice, we move the cursor back to position
      # thus: LF, content, whitespace, LF, content
      printf '\r%s%*s\r%s' "$line" "$ws" " " "$line"
    fi
  done
  echo
}

如下使用:

rm -rv -- * 2>&1 | oneline

为了更安全地测试这一点,可以使用:

for f in 'first line' 'second line' '3rd line'; do echo "$f"; sleep 1; done | oneline

...您会看到该测试显示 first line 一秒钟,然后是 second line 一秒钟,然后是 3rd line 一秒钟。

【讨论】:

  • 2>&1 部分的作用是什么?
  • @Blaxou,以确保我们正确处理写入 stderr 的内容。
  • 为我工作。我跳过了这样的功能:touch ff1 ff2 ff3;rm -fv ff1 ff2 ff3 |while read -r line;do ws=$(( COLUMNS - ${#line} ));printf '\r%s%*s\r%s' "$line" "$ws" " " "$line";sleep 2;done;echo
  • @Blaxou,您能否提供一个比“不起作用”更准确的行为描述?
  • 查看修改后的版本,它通过仅打印输出的前 COLUMNS 个字符来修复大小写。
【解决方案2】:

如果你想要一个“状态行”结果,它显示程序输出的最后一行,当它出现时,该行被下一行覆盖,你可以通过一个简短的 shell 发送命令的输出,而像这样循环:

  YourCommand | while read line ; do echo -n "$line"$'  ...[lots of spaces]... \r' ; done

如果较短的行出现在较长的行之后,则需要[大量空格]。短行需要覆盖较长行的文本,否则您会看到长行的残留字符。

echo -n $' ... \r' 将不带换行符的文字回车发送到屏幕,这会将位置移回行的前面,但不会向下移动。

如果您希望命令中的文本仅在 1 长行中输出,那么 通过这个 sed 命令管道输出任何命令,它应该用空格替换回车符。这会将输出全部放在一行上。如果需要,您可以将空格更改为另一个分隔符。

 your command  | sed ':rep; {N;}; s/\n/ /; {t rep};'

:rep;是一个非命令,用于标记 {t rep} 命令中的去向。

{N;} 将当前行连接到下一行。 它不会删除回车,只是将 2 行放入缓冲区中以用于后续命令。

s/\n/ /;表示用空格字符替换回车符。它们的空格在第二个和第三个/字符之间。 您可能需要替换 \r\n ,具体取决于文件是否有换行符。 UNIX 文件不会,除非它们来自 pc 并且没有被转换。

{t 代表};表示如果在 s/// 命令中找到匹配项,则转到 :rep;标记。

这将继续加入行,删除 \n,然后跳转到 :rep;直到没有更多喜欢的人加入为止。

【讨论】:

  • 空间到底在哪里?在:rep;{N;}; 之间?
  • @Blaxou: 空间在 s/\n/[space]/;命令它说用文字空格字符替换 \n (回车)字符。空格在 s/x/y/ 中的第二个 / 和第三个 / 之间;命令。
  • 它似乎不起作用......我试图用sed ':rep; {N;}; s/\r/ /; {t rep};'替换sed ':rep; {N;}; s/\n/ /; {t rep};',它只显示每行的输出
  • 输出可能同时包含\r和\n,所以你可能需要s/\r\n/ /;让回车和换行符被替换。要查看从上一个命令中输出的字节,请通过“| od -c -t x1”之类的命令运行输出,这会将输出打印为字符和字节。寻找像 10 == \r 和 13 == \n 这样的字节,看看输出中有哪些。
  • 只包含\n字节,没有\r
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 2014-10-12
  • 2021-10-26
相关资源
最近更新 更多