我正在尝试提取 正在检索的文件的下载进度curl
。
我尝试了这个,但这不起作用:
curl --progress-bar http://127.0.0.1/test.tar.bz2 -o test.tar.bz2 2>/dev/stdout | sed -r 's/[# ]//g;s/^/#/g'
不过这个sed
表达似乎没问题:
$ echo '######## 10.2%' | sed -r 's/[# ]//g;s/^/#/g'
#10.2%
谁能指出我做错了什么?
答案1
主要问题是sed
适用于线因此,在到达第一个命令之前它不会执行任何操作\n
,并且在您的命令完成之前不会发生这种情况。您可以通过将\r
s 与s交换来解决此问题\n
:
$ curl --progress-bar http://127.0.0.1/test.tar.bz2 -o test.tar.bz2 2>&1 |
tr $'\r' $'\n' | sed -r 's/[# ]+/#/g;'
然而,这会给您带来缓冲,缓冲sed
现在将作用于多组行。我一起破解的最终解决方案是将错误重定向到一个文件,然后处理该文件:
$ curl --progress-bar http://127.0.0.1/test.tar.bz2 -o test.tar.bz2 2>er
$ while :; do
echo -ne "$(tr $'\r' $'\n' < er | tail -n 1 | sed -r 's/^[# ]+/#/;')\r";
done
上面的命令将解析错误文件(er
)并打印结果并\r
使其不断更新。您需要手动摆脱它。
来自匿名用户的建议:您还可以放在这些命令的stdbuf -oL
前面tr
,sed
从而修改这些命令的缓冲行为。
答案2
尝试 perl:
curl --progress-bar http://127.0.0.1/test.tar.bz2 -o test.tar.bz2 2>&1 | perl -015 -n -e 'print "$1\n" if (/[#]* ([\d]+)/);'
在哪里:
- 2>&1 将 stderr 分配给 stdout 所在的位置,在本例中是到 perl 的管道
- -015 设置输入记录分隔符为回车符(八进制15)
- -e 是一行代码,在本例中,它跳过任何前导 # 并将后续整数提取到 $1 中,只要提取成功,就会打印 $1 。
- -n 将 -e 提供的行包装在“while(<>){}”中,逐条记录地读取输入,直到 EOF,其中我们安排每个记录用 CR 和 -0 分隔