Bash 与grep while prinf相比,使用rege从日志文件中提取值更简单、更优雅

Bash 与grep while prinf相比,使用rege从日志文件中提取值更简单、更优雅,bash,grep,printf,Bash,Grep,Printf,我有几个日志文件看起来像: #LOGa# 180.149.126.169 ## 85 with value 350.00000000000000000000 due brand: 350.00000000000000000000 country: 0 {2020-11-26_11-01-00} #DETAILS_hits# 180.149.126.169 ## hits=([brand/17]="1" [brand/18]="1" [no_brand]=&

我有几个日志文件看起来像:

#LOGa# 180.149.126.169 ## 85 with value 350.00000000000000000000 due brand: 350.00000000000000000000 country: 0 {2020-11-26_11-01-00}
#DETAILS_hits# 180.149.126.169 ## hits=([brand/17]="1" [brand/18]="1" [no_brand]="1" ) {2020-11-26_11-01-00}
#LOG_brand# 180.149.126.169 ## BRANDS=([anyBrand]="1" ) {2020-11-26_11-01-00}
#LOG_country# 180.149.126.169 ## COUNTRY=([anyCountry/17]="1" [anyContinent/18]="1" ) {2020-11-26_11-01-00}
我想提取一些特殊对数线的圆顶值

我当然可以和你一起去

grep -HiRE "(#LOGa#)(.+)(## )(.+)" --include \myFile.log | while read _ ip _ rank _ value _ _ valueBrand _ _ valueCountry _ ; do printf "%.0f %.0f\n" $valueBrand $valueCountry; done
但这不是一种更优雅的方式, 类似

cleanME myFile.log "(#LOGa#)($ip)(## )($rank)(with value)($value)(due brand:)($valueBrand)(country:)($valueCountry)(.*)" "$valueBrand.0f $valueCountry.0f"

当然,我可以构建这样的函数,但我不记得它比grep+while+printf更好。如果您选择
Perl
,请尝试:

perl -ne '/^#LOGa#\s+([\d.]+)\s+##\s+([\d.]+)\s+with value\s+([\d.]+)\s+due brand:\s+([\d.]+)\s+country:\s+([\d.]+)/ && printf "%.0f %.0f\n", $4, $5' myFile.log
所提供输入的输出:

350 0
  • 选项
    -n
    告诉
    Perl
    sed
    的形式逐行处理输入文件
  • 选项
    -e
    启用一行程序
  • 语法
    /regex/&&printf…
    仅当行 将正则表达式匹配为
    grep
  • 正则表达式中的参数创建捕获组和匹配的子字符串 可以使用
    $1
    $2
    。。。按顺序

我不确定这是否更好,但是考虑一下:

find . -type f -name myFile.log -print | xargs sed -En 's/^#LOGa# .+ ## .+ with value [0-9.-]+ due brand: ([0-9.-]+) country: ([0-9]+).*$/\1 \2/1;Tx;p;:x'
说明:

find
——在当前目录(
)中递归查找名为myFile.log(
-name myFile.log
)和
-print
的所有文件(
-type f
)。(
sed
没有像
grep
这样的
-R
选项)将此管道传输到
xargs
,对于每个管道,xargs将调用流编辑器
sed
,使用扩展的regexp语法(
-E
)并且不自动打印行(
-n
)。替换(
s/
)给定的regexp,使用分组运算符捕获valueBrand和valueCountry,并替换第一次出现(
/1
)时括号(
\1\2
)中捕获的整行值。然后,如果此替换未发生,则跳转到标签x(
;Tx
);否则
p
打印该行。然后是标签x(
;:x
)和end(仅退出)


我不确定您是否有意截断输出中的小数位;要做到这一点,您必须通过
bash
printf
语句(
在读取b时;do printf“%.0f%.0f”ab;done
)或其他程序,或者以另一种方式执行。或者,如果您真的想将(即不是四舍五入)截断到小数点后零位,您可以使用
品牌:([0-9-]+)\.[0-9]*
而不是
品牌:([0-9-]+)
。这只是将小数点和尾数从字符串中排除,然后将其删除。

为了更好地理解问题,请在问题中添加示例预期输出。为什么不只添加
awk
是不是一种更优雅的方式
你的问题到底是什么?“优雅”可能是基于观点的。我们不知道你“不记得”什么。