【问题标题】:Complex bash pipeline works in jumps复杂的 bash 管道在跳跃中工作
【发布时间】:2012-03-26 21:13:05
【问题描述】:

我的意图是在一行中输出递归wget 的日志,类似于“状态栏”。所以我组装了这条管道(我的wget 电话有更多选择,但我只留下了对所描述的问题至关重要的那些):

wget -r -nv ftp://example.com 2>&1 | cut -c1-80 | xargs -I line echo -ne 'line\033[0K\r'

让我解释一下我的意思。也许我的命令有问题。

  • -r 表示“递归下载”;
  • -nv 使有关每次下载的消息简短,例如:“时间:URL -> 本地文件”;
  • &2>1 将 stderr 重定向到 stdout,以便我可以通过管道处理消息;
  • | cut -c1-80 将输出行剪切为 80 个字符。有时 URL 和本地文件名一起构成一个长字符串,将一行分成 2 行或更多行。而且我需要它适合单行控制台。 80站在这里只是一个例子。在我的脚本中,我使用tput cols 确定控制台宽度;
  • | xargs -I line echo -ne 'line\033[0K\r' 打印上一个命令的输出并添加两个特殊字符: \033[OK - 行尾,如果之前的输出中还有任何字符,它将清除行的其余部分;和 \r - 回车,将光标设置到当前行的开头。

所以想要的行为是:

  1. wget 下载文件并尝试将有关此的通知打印到标准输出
  2. cut 立即截取 wget 的输出并将其修剪为 80 个字符
  3. xargs 捕捉到修剪过的线条并立即用特殊字符打印出来

所以我应该看到显示当前下载的某种状态栏。

但是! 我所看到的只是 10 到 60 秒内没有发生任何事情,然后在大约 1 秒内打印出所有关于在此期间完成的下载的消息。他们实际上以我想要的方式打印,但速度非常快。然后再一次,暂停,1 秒内的另一部分消息,依此类推。所以一切都很好,除了立即-ness。

当我删除xargs 部分时,消息会立即显示(但不是一行)。当我删除cut 调用时,它们是即时的,但有时会用一些非常长的 URL 换行。如果我从echo 调用中仅删除特殊字符,则输出仍然是“跳跃”而不是一行。

要重现这一点,您可以将“ftp://example.com”替换为可用于测试递归下载的任何 URL(HTTP 也可以),即如果 FTP 有许多文件和目录,并且以防万一HTTP 的许多链接指向具有更多链接的页面(不要担心它可能会尝试下载所有 Internet,因为 -r 选项的默认递归级别为 5)。如果你不能重现这个,那么我认为这是我的发行版有问题,请在下面的 cmets 部分写下它。

附:如果您知道为wget 组织状态栏的更好方法,非常欢迎您的 cmets。但我正在学习 Bash,想知道是什么导致了这种奇怪的行为。也许有一些关于管道或echoxargs 我不知道。所以问题是为什么这条管道如此有效,而不是像我预期的那样。

【问题讨论】:

    标签: linux bash pipe statusbar xargs


    【解决方案1】:

    问题是输出缓冲,有解决办法:Turn off buffering in pipe

    不幸的是,当我尝试应用它们时,我收到了xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option

    你必须尝试不同的方法,我认为xargs 不是这个任务的好选择,试试 awk、perl、python、ruby...

    【讨论】:

    • 谢谢!现在我知道是什么导致了问题(缓冲)以及如何绕过它(awk)。是的,xargs 确实不适合字符串操作。
    • 因此我的管道现在就像:wget -r -nv http://example.com 2>&1 | awk -W interactive '{ORS=""; print substr($0,1,80) "\033[0K\r" }'-W interactive 使 awks 不缓冲输出,ORS="" 给我们 print 没有换行符。
    【解决方案2】:

    xargs 收集多行输入并仅调用一次命令(在您的情况下为回显)*。将“-L 1”添加到 xargs 的参数中,看看是否有帮助。

    * xargs 会在命令行过长时使用更多的命令调用,但会尽可能多地分组。

    【讨论】:

    • 看起来很合理,我不知道 xargs,但是:1)它没有帮助,你尝试过它并且它有效吗? 2) 如果我删除| cut 管道,它会按预期工作,没有收集线。
    • 无论如何,感谢有关-L 选项的提示。我了解到它与-I 有点不兼容。这就是手册页所说的。
    猜你喜欢
    • 1970-01-01
    • 2021-08-24
    • 2015-06-28
    • 2018-12-29
    • 1970-01-01
    • 2014-02-26
    • 2018-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多