我正在编写一个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
答案 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?