我正在尝试编写一个涉及以下内容的脚本快照RAID,其中 的进度输出snapraid sync
带有时间戳并记录到文件和标准输出中。我面临的问题是将snapraid sync
其进度输出到每秒刷新的一行上。这意味着当在脚本中运行它时,剩下的唯一输出是类似100% completed, 7737 MB accessed in 0:00
.您无法回顾命令是如何运行的。
通过使用ts
、sed
和tee
,我可以部分实现我的目标:
#!/bin/bash
LOG_FILE="/tmp/snapRAID.log"
exec 1>> >(ts '[%Y-%m-%d %H:%M:%S]') 2>&1
snapraid sync | sed -e 's/\r/\n/g' | tee >(ts "[%Y-%m-%d %H:%M:%S]" >> $LOG_FILE)
stdout
这将导致和产生以下输出/tmp/snapRAID.log
(以及 的其余输出snapraid sync
):
[2023-04-23 16:24:51] 0%, 0 MB
[2023-04-23 16:24:51] 5%, 552 MB
[2023-04-23 16:24:51] 12%, 1332 MB
[2023-04-23 16:24:51] 17%, 1942 MB
[2023-04-23 16:24:51] 21%, 2311 MB
[2023-04-23 16:24:51] 27%, 3044 MB, 622 MB/s, 1188 stripe/s, CPU 14%, 0:00 ETA
[2023-04-23 16:24:51] 35%, 3836 MB, 656 MB/s, 1253 stripe/s, CPU 14%, 0:00 ETA
[2023-04-23 16:24:51] 42%, 4612 MB, 676 MB/s, 1306 stripe/s, CPU 15%, 0:00 ETA
[2023-04-23 16:24:51] 49%, 5005 MB, 636 MB/s, 1334 stripe/s, CPU 15%, 0:00 ETA
[2023-04-23 16:24:51] 58%, 5493 MB, 617 MB/s, 1400 stripe/s, CPU 16%, 0:00 ETA
[2023-04-23 16:24:51] 67%, 5987 MB, 581 MB/s, 1449 stripe/s, CPU 16%, 0:00 ETA
[2023-04-23 16:24:51] 75%, 6415 MB, 564 MB/s, 1470 stripe/s, CPU 16%, 0:00 ETA
[2023-04-23 16:24:51] 80%, 6694 MB, 536 MB/s, 1429 stripe/s, CPU 15%, 0:00 ETA
[2023-04-23 16:24:51] 84%, 6916 MB, 507 MB/s, 1376 stripe/s, CPU 15%, 0:00 ETA
[2023-04-23 16:24:51] 92%, 7314 MB, 498 MB/s, 1388 stripe/s, CPU 15%, 0:00 ETA
[2023-04-23 16:24:51] 97%, 7574 MB, 433 MB/s, 1268 stripe/s, CPU 13%, 0:00 ETA
问题是这个输出不是实时的 -snapraid sync
只有在运行完成后,整个输出才会出现在标准输出和日志文件中。如果我删除该tee
元素并将其输出到stdout
.如果我想了解snapraid sync
运行中的进展情况,这对我没有帮助。该测试实例在几秒钟内完成同步,但我想要运行它的机器可能需要几个小时,并且我希望能够在运行过程中检查命令的进度,同时还能够回顾运行之前发生的事情并查看时间戳。
我尝试过以下一些想法,但没有成功:
unbuffer snapraid sync | sed -e 's/\r/\n/g' | tee >(ts "[%Y-%m-%d %H:%M:%S]" >> $LOG_FILE)
snapraid sync | sed -u -e 's/\r/\n/g' | tee >(ts "[%Y-%m-%d %H:%M:%S]" >> $LOG_FILE)
有谁知道我如何才能使这个带有时间戳的换行输出实时发生?
提前谢谢了!
答案1
sed
缓冲其输出,因为它不会发送到 tty。某些sed
实现支持-u
禁用该缓冲的选项,或者您可以使用stdbuf
, withsed
或 with tr
,这会更合适,特别是\r
考虑\n
到sed
.
snapraid sync |
stdbuf -oL tr '\r' '\n' |
ts '[%Y-%m-%d %H:%M:%S]' |
tee -a "$LOG_FILE"
如果snapraid
在不进入终端时也缓冲其输出,您可以stdbuf
在那里尝试相同的技巧,尽管您可能希望在那里stdbuf -o0
(无缓冲)而不是stdbuf -oL
(基于行的缓冲):
stdbuf -o0 snapraid sync |
stdbuf -oL tr '\r' '\n' |
ts '[%Y-%m-%d %H:%M:%S]' |
tee -a "$LOG_FILE"
无论如何,stdbuf
这也不是标准命令,但在可用的情况下,应该比使用伪 tty 尝试说服应用unbuffer
程序expect
不要缓冲但已知会破坏输出的脚本更可取。
-u
都不是标准选项sed
。
请注意,许多sed
实现还会提前读取一行,以便能够知道地址何时$
匹配,这意味着即使它到达终端设备,输出也会有一行延迟。
ts
是一个明确禁用缓冲的perl
脚本。$| = 1
在我的测试中,tee
即使目标文件和标准输出都不是终端设备,GNU 至少不会缓冲其输出。
顺便说一句,从安全角度来看,在世界可写目录中写入具有固定名称的文件是/tmp
不好的做法,应该避免。要么使用它mktemp
来保证您在那里获得自己的临时文件,要么将该文件写入您的目录,例如其他人都无法在其中植入恶意符号链接。