【问题标题】:awk: how to extract 2 patterns from a single line and then concatenate them?awk:如何从一行中提取 2 个模式,然后将它们连接起来?
【发布时间】:2020-03-31 10:21:51
【问题描述】:

我想在每行中找到 2 个模式,然后在它们之间用破折号作为分隔符打印它们。以下是行示例:

20200323: #5357 BEAR_SPX_X15_NORDNET_D1 {CU=DKK, ES=E, II=DK0061205473, IR=NRB, LN=BEAR SPX X15 NORDNET D1, MIC=FNDK, NS=1, PC=C, SE=193133, SG=250, SN=193133, TK="0.01 to 100,0.05 to 500,0.1", TS=BEAR_SPX_X15_NORDNET_D1, TY=W, UQ=1}
20200323: #5358 BULL_SPX_X10_NORDNET_D2 {CU=DKK, ES=E, II=DK0061205556, IR=NRB, LN=BULL SPX X10 NORDNET D2, MIC=FNDK, NS=1, PC=P, SE=193132, SG=250, SN=193132, TK="0.01 to 100,0.05 to 500,0.1", TS=BULL_SPX_X10_NORDNET_D2, TY=W, UQ=1}
20200323: #5359 BULL_SPX_X12_NORDNET_D2 {CU=DKK, ES=E, II=DK0061205630, IR=NRB, LN=BULL SPX X12 NORDNET D2, MIC=FNDK, NS=1, PC=P, SE=193131, SG=250, SN=193131, TK="0.01 to 100,0.05 to 500,0.1", TS=BULL_SPX_X12_NORDNET_D2, TY=W, UQ=1}

鉴于以上几行,运行脚本后我想要的输出应如下所示:

BEAR_SPX_X15_NORDNET_D1 - DK0061205473
BULL_SPX_X10_NORDNET_D2 - DK0061205556
BULL_SPX_X12_NORDNET_D2 - DK0061205630

第一个字母数字值(例如 BULL_SPX_X12_NORDNET_D2)始终位于一行的第三个位置。 第二个字母数字值(例如 DK0061205630)可以位于不同的位置,但始终以“II=”开头,并且长度始终为 12 个字符。

我尝试使用以下脚本来实现我的任务:

 13 regex='II=.\{12\}'
 14 while IFS="" read -r line; do
 15     matchedString=`grep -o $regex littletest.txt | tr -d 'II=,'`
 16     awk /II=/'{print $3, " - ", $matchedString}' littletest.txt > temp.txt
 17 done <littletest.txt

我的思考过程和意图/假设:

第 13 行定义了一个正则表达式模式来匹配以“II="

开头的字母数字字符串

在第 15 行中,变量“matchedString”被分配了一个值,该值通过正则表达式从一行中提取,前面的“II=”被删除。

第 16 行使用 awk 表达式检测所有包含“II=”的行,然后打印在每个输入文件的行上找到的第三个字符串,并打印在前一行中定义的匹配字符串模式的值剧本。所以我希望此时应该将一对提取的模式(例如 BEAR_SPX_X15_NORDNET_D1 - DK0061205473)传输到 temp.txt 文件中。

第 17 行正在获取一个输入文件以供脚本使用。

但是,在运行脚本后,我没有得到所需的输出。这是我得到的示例:

BEAR_SPX_X15_NORDNET_D1
20200323: #5357 BEAR_SPX_X15_NORDNET_D1 {CU=DKK, ES=E, II=DK0061205473, IR=NRB, LN=BEAR SPX X15 NORDNET D1, MIC=FNDK, NS=1, PC=C, SE=193133, SG=250, SN=193133, TK="0.01 to 100,0.05 to 500,0.1", TS=BEAR_SPX_X15_NORDNET_D1, TY=W, UQ=1}

我怎样才能实现我之前描述的所需输出?

【问题讨论】:

    标签: regex bash awk


    【解决方案1】:
    $ awk -v OFS=' - ' 'match($0,/II=/){print $3, substr($0,RSTART+3,12)}' file
    BEAR_SPX_X15_NORDNET_D1 - DK0061205473
    BULL_SPX_X10_NORDNET_D2 - DK0061205556
    BULL_SPX_X12_NORDNET_D2 - DK0061205630
    

    【讨论】:

    • Ed -Awk- Morton rulez!不错的解决方案!
    【解决方案2】:

    只是尝试 awk。

    awk  'BEGIN{ FS="[II=, ]+" ; OFS=" - " } {print $3, $8}' file.txt
    

    【讨论】:

    • OP 在问题The second alphanumeric value (e.g. DK0061205630) can be at various positions 中说,所以你不能依赖它是$8 或任何其他固定位置。不幸的是,他们发布的示例输入没有反映这一点,
    【解决方案3】:

    使用支持正则表达式的 gawk (gnu awk) 作为字段分隔符 (FS) ,并考虑到文件中的每一行具有完全相同的格式/相同数量的字段,这在我的测试中可以正常工作:

    awk '{print $3,$9}' FS="[ ]|II=" OFS=" - " file1
    #or FS="[[:space:]]+|II=|[,]" if you might have more than one space between fields
    

    结果

    BEAR_SPX_X15_NORDNET_D1 - DK0061205473
    BULL_SPX_X10_NORDNET_D2 - DK0061205556
    BULL_SPX_X12_NORDNET_D2 - DK0061205630
    

    由于II= 部分可以在任何地方,这个技巧也可以在解析文件两次的情况下起作用:

    paste -d "-" <(awk '{print $3}' file1) <(awk '/II/{print $2}' RS="[ ]" FS="=|," file1)
    

    【讨论】:

    • OP 确实提到 第二个字母数字值(例如 DK0061205630)可以在不同的位置,但它总是以“II=" 开头。
    • @blhsing 显然我错过了那部分!
    • 每个 awk 都支持正则表达式作为字段分隔符 (FS)。它使用正则表达式作为需要 gawk 的记录分隔符 (RS)。在 RS="[ ]"FS="[ ]|II=" 中,您不需要将空格放在括号表达式中,它已经像 RS=" "FS=" |II=" 一样直接。
    猜你喜欢
    • 1970-01-01
    • 2010-10-18
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    相关资源
    最近更新 更多