我用来gradle run
启动 REST 服务器。 REST 服务器的输出如下所示:
XXX.XXX.XX.XXX - <moreinfo>
randomtext
randomtext
XXX.XXX.XX.XXX - <moreinfo>
XXX.XXX.XX.XXX - <moreinfo>
randomtext
XXX.XXX.XX.XXX - <moreinfo>
XXX.XXX.XX.XXX
这是 IP 地址,随机文本是错误消息。遗憾的是,所有输出都定向到标准输出。
如何将所有以 IP 地址开头的行定向到名为 的文件,err.log
并将每隔一行定向到all.log
?
不幸的是,gradle run
只能启动一次并且不能停止,因为它是 REST 服务器。
也许使用tee
,grep
组合?
答案1
在 Bash 中,您可以使用流程替代带 T 恤:
tee >(grep XXX > err.log) | grep -v XXX > all.log
这会将所有匹配 XXX 的行放入err.log
,并将所有行放入all.log
。>( ... )
在括号中创建进程并将其标准输出连接到管道。这适用于嘚还有其他现代贝壳。
您还可以使用以下pee
命令更多实用程序:
pee "grep XXX > err.log" "grep -v XXX > all.log"
pee
将标准输入重定向到多个命令(“管道的三通”)。
另一种选择是使用 awk:
awk '{ if (/^([0-9]{1,3}\.){3}[0-9]{1,3}/) { print > "err.log" } else { print > "all.log" } }'
这只是针对表达式测试每一行,并将整个内容写入err.log
是否匹配或all.log
不匹配。
awk 正则表达式也适合grep -E
(尽管它确实匹配一些错误的地址 -999.0.0.0
等等 - 但这可能不是问题)。
答案2
因此,它看起来gradle run
不符合tee
、pee
和grep
io 重定向。它总是在 4096 字节后停止读取。
为了避免这个问题,我read
将每一行gradle run
.我还没有测试过,但我猜读取超过 4k 个字符长的行也会失败。
无论如何,这是专门解决我的问题的代码:
#!/bin/bash
STDOUTLOG="/log/stdout.txt"
STDERRLOG="/log/stderr.txt"
while read -r line; do
[[ $line =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}.* ]] && printf '%s\n' "$line" >> "$STDERRLOG" && continue
printf '%s\n' "$line" >> "$STDOUTLOG"
done < <(gradle run)