如何监视ssh文件传输和输出到日志文件的进度

时间:2011-05-16 15:56:27

标签: bash unix scripting

我正在编写一个bash脚本来定期将数据传输到远程系统。我有一个生成流的本地命令,以及一个使用它的远程命令,所以我做的是这样的:

generate_data | ssh remoteserver.example.com consume_data

(我设置了ssh键,所以我可以非交互式地执行此操作。)这样可以正常工作。但是,由于这将是一个自动化过程(作为一个cron作业运行),有时可能会在有限的带宽上传输大量数据,我希望能够在我的日志文件中定期进行更新。我原本以为使用pv(管道查看器),这是我能想到的最好的:

generate_data | pv -fb | ssh remoteserver.example.com consume_data

同样,它有效... 但是 pv真的是用终端输出写的,所以我最终看起来像是

的日志
2.06MB^M2.19MB^M2.37MB^M 2.5MB^M2.62MB^M2.87MB^M3MB^M3.12MB^M3.37MB

我更喜欢

行的日志消息
<timestamp> 2.04MB transferred...
<timestamp> 3.08MB transferred...

如果有人对如何做到这一点有任何聪明的想法,或者使用pv的不同论点或通过其他机制,我将不胜感激。

编辑:感谢您的回答。当然,有很多可能的家庭酿造解决方案;我希望找到一些可以“开箱即用”的东西。 (并不是说我排除了自酿;这可能是最简单的事情。因为pv已经完成了我所需要的98%,所以我宁愿不重新发明它。)< / p>

PostScript: 以下是我最终使用的内容,希望它可能在某些时候帮助其他人。

{ generate_data | pv -fbt -i 60 2>&3 | ssh remoteserver consume_data } 3>&1 | awk -vRS='\r' '{print $1 " transferred in " $2; fflush();}' >> logfile

5 个答案:

答案 0 :(得分:5)

如果你想坚持pv,你可以稍微后处理它的输出。至少将CR转换为LF。

{ generate_data | pv -bft 2>&3 | consume_data >/dev/null; } 3>&1 | tr '\015' '\012'

使用awk进行更高级的处理。

{ generate_data | pv -bft 2>&3 | consume_data >/dev/null; } 3>&1 |
awk -vRS='\r' '{print $2, $1 " transferred"}'

但请记住,标准文本处理实用程序只会在每行末尾刷新输出,如果它们正在打印到终端。因此,如果将pv传递给其输出转到管道或文件的其他实用程序,则由于缓冲将导致不可忽略的延迟。如果你有GNU awk或其他具有fflush函数的实现(它是常见的但不是标准的),那么让它在每一行刷新它的输出:

{ generate_data | pv -bft 2>&3 | consume_data >/dev/null; } 3>&1 |
awk -vRS='\r' '{print $2, $1 " transferred"; fflush()}'

答案 1 :(得分:2)

这是一个小红宝石脚本,我相信你想要的。由于ruby的开销,我每秒只能获得大约1MB的文件复制到本地文件系统,但是你提到管道的带宽有限,所以这可能没问题。我从rails(actionview)中提取了number_to_human_size函数。

#!/usr/bin/ruby                                                                                                                           
require 'rubygems'
require 'active_support'

# File vendor/rails/actionpack/lib/action_view/helpers/number_helper.rb, line 87                                                          
def number_to_human_size(size)
  case
    when size < 1.kilobyte: '%d Bytes' % size
    when size < 1.megabyte: '%.1f KB'  % (size / 1.0.kilobyte)
    when size < 1.gigabyte: '%.1f MB'  % (size / 1.0.megabyte)
    when size < 1.terabyte: '%.1f GB'  % (size / 1.0.gigabyte)
    else                    '%.1f TB'  % (size / 1.0.terabyte)
  end.sub('.0', '')
rescue
  nil
end

UPDATE_FREQ = 2
count = 0
time1 = Time.now

while (!STDIN.eof?)
  b = STDIN.getc
  count += 1
  print b.chr
  time2 = Time.now
  if time2 - time1 > UPDATE_FREQ
    time1 = time2
    STDERR.puts "#{time2} #{number_to_human_size(count)} transferred..."
  end
end

答案 2 :(得分:1)

你可能会看一下吧:http://clpbar.sourceforge.net/

  

Bar是一个复制流的简单工具   数据和打印显示   用户在stderr上显示(a)金额   传递的数据,(b)吞吐量   数据传输,以及(c)   转移时间,或者,如果总大小   数据流的已知,   估计剩余时间,什么   数据传输的百分比   已经完成,还有一个进度条。

     

Bar最初是为   估计金额的目的   转移大量所需的时间   (很多,几千兆字节)的数据   一个网络。 (通常在SSH / tar中   管。)

答案 3 :(得分:1)

源代码位于http://code.google.com/p/pipeviewer/source/checkout,因此您可以编辑一些C并使用PV!

编辑: 是的获取源然后编辑display.c的第578行,其中包含以下代码:

    display = pv__format(&state, esec, sl, tot);
if (display == NULL)
    return;

if (opts->numeric) {
    write(STDERR_FILENO, display, strlen(display)); /* RATS: ignore */
} else if (opts->cursor) {
    pv_crs_update(opts, display);
} else {
    write(STDERR_FILENO, display, strlen(display)); /* RATS: ignore */
    write(STDERR_FILENO, "\r", 1);
}

您可以将“\ r”更改为“\ n”并重新编译。通过每次将它放在一个新行上,这可以为您提供更有用的输出。如果需要,您也可以尝试重新格式化整个输出字符串。

答案 4 :(得分:0)

也许是一个小的perl程序将STDIN复制到STDOUT并将其进度打印到STDERR?