【问题标题】:Merge two files, line by line, after matching pattern in a new line在新行中匹配模式后,逐行合并两个文件
【发布时间】:2018-11-30 04:05:52
【问题描述】:

如果有匹配项,我需要合并 2 个文件。非静态中的匹配是随机的,但总是在一个特定的标签之后

文件 1

<can update="x" site="merge-xml-01" site_id="foo.com" xmltv_id="foo@com">foo@com</can>
<can update="x" site="merge-xml-02" site_id="bar.com" xmltv_id="bar@com">bar@com</can>
<can update="x" site="merge-xml-03" site_id="xxx.com" xmltv_id="xxx@com">xxx@com</can>

文件 2

<can offset="u" same_as="foo.com" id="foo 01">foo 01</can>
<can offset="u" same_as="foo.com" id="foo 02">foo 02</can>
<can offset="u" same_as="bar.com" id="bar 01">bar 01</can>
<can offset="u" same_as="xxx.com" id="xxx 01">xxx 01</can>
<can offset="u" same_as="xxx.com" id="xxx 02">xxx 02</can>
<can offset="u" same_as="xxx.com" id="xxx 03">xxx 03</can>

我需要像这样将文件编号设为 3

<can update="x" site="merge-xml-01" site_id="foo.com" xmltv_id="foo@com">foo@com</can>
<can offset="u" same_as="foo.com" id="foo 01">foo 01</can>
<can offset="u" same_as="foo.com" id="foo 02">foo 02</can>
<can update="x" site="merge-xml-02" site_id="bar.com" xmltv_id="bar@com">bar@com</can>
<can offset="u" same_as="bar.com" id="bar 01">bar 01</can>
<can update="x" site="merge-xml-03" site_id="xxx.com" xmltv_id="xxx@com">xxx@com</can>
<can offset="u" same_as="xxx.com" id="xxx 01">xxx 01</can>
<can offset="u" same_as="xxx.com" id="xxx 02">xxx 02</can>
<can offset="u" same_as="xxx.com" id="xxx 03">xxx 03</can>

我希望清楚,如果文件1中的“site_id=”标签与文件2中的标签“same_as=”匹配,我需要合并数据。

老实说,我不知道我能做些什么才能得到这个结果,我检查了很多帖子,但所有的合并数据都在同一行,我在新行上找不到合并数据的东西。

如果可以使用 sed 或 awk,我喜欢,但欢迎提出任何建议。

谢谢你的建议。

【问题讨论】:

    标签: bash shell awk sed


    【解决方案1】:

    假设 file2 是按 key 排序的

    $ awk -F' |=' 'NR==FNR {for(i=1;i<NF;i++) if($i=="site_id") {a[$(i+1)]=$0; break}; next} 
                           {k=""; for(i=1;i<NF;i++) if($i=="same_as") {k=$(i+1); break}
                            if(!p[k]++) print a[k]}1' file1 file2
    
    <can update="x" site="merge-xml-01" site_id="foo.com" xmltv_id="foo@com">foo@com</can>
    <can offset="u" same_as="foo.com" id="foo 01">foo 01</can>
    <can offset="u" same_as="foo.com" id="foo 02">foo 02</can>
    <can update="x" site="merge-xml-02" site_id="bar.com" xmltv_id="bar@com">bar@com</can>
    <can offset="u" same_as="bar.com" id="bar 01">bar 01</can>
    <can update="x" site="merge-xml-03" site_id="xxx.com" xmltv_id="xxx@com">xxx@com</can>
    <can offset="u" same_as="xxx.com" id="xxx 01">xxx 01</can>
    <can offset="u" same_as="xxx.com" id="xxx 02">xxx 02</can>
    <can offset="u" same_as="xxx.com" id="xxx 03">xxx 03</can>
    

    ps。这应该比其他大文件解决方案快得多。

    【讨论】:

    • 您的解决方案也运行良好!谢谢你的回答。说声谢谢我的建议总是有效的,如果你在米兰附近,一小撮啤酒可以给你:)
    【解决方案2】:

    如果你肯定知道这些格式是一致的,并且总是在一行上......

    $: cat c $ file 1 is a, file 2 is b
    #! /bin/env bash
    
    while read -r line
    do pat="${line##* site_id=\"}"
       pat="${pat%%\"*}"
       echo "$line"
       grep " same_as=[\"]$pat[\"] " b
    done < a
    
    $: c
    <can update="x" site="merge-xml-01" site_id="foo.com" xmltv_id="foo@com">foo@com</can>
    <can offset="u" same_as="foo.com" id="foo 01">foo 01</can>
    <can offset="u" same_as="foo.com" id="foo 02">foo 02</can>
    <can update="x" site="merge-xml-02" site_id="bar.com" xmltv_id="bar@com">bar@com</can>
    <can offset="u" same_as="bar.com" id="bar 01">bar 01</can>
    <can update="x" site="merge-xml-03" site_id="xxx.com" xmltv_id="xxx@com">xxx@com</can>
    <can offset="u" same_as="xxx.com" id="xxx 01">xxx 01</can>
    <can offset="u" same_as="xxx.com" id="xxx 02">xxx 02</can>
    <can offset="u" same_as="xxx.com" id="xxx 03">xxx 03</can>
    

    【讨论】:

    • 如果你在米兰,一小撮啤酒正等着你:)
    • 是的,您的脚本也运行良好,但与其他人有同样的问题,忽略并且不保存最后一场比赛,我可以绕过这个麻烦,在最后添加一个假行,但是是strage...我在windows下使用一个子系统linux....也许是问题..
    • 查看这个:stackoverflow.com/questions/729692/… 了解为什么您需要在最后一行末尾添加 \n
    • 别担心,我知道,我在运行每个脚本之前都会使用工具 dos2unix ;)
    • 嗯。我明确删除了换行符并确认它已经消失,并希望它对我来说同样失败,但事实并非如此。您使用的是哪个版本的 grep? grep (GNU grep) 3.0 在这里。
    【解决方案3】:

    逐行读取文件,找到 URL 并在第二个文件中搜索。

    while read -r line; do
            echo "$line" >> file3
            url=$(sed 's/.*site_id="\([^"]\+\)".*/\1/' <<< $line)
            grep $url file2 >> file3
    done < file1
    
    $ cat file3
    <can update="x" site="merge-xml-01" site_id="foo.com" xmltv_id="foo@com">foo@com</can>
    <can offset="u" same_as="foo.com" id="foo 01">foo 01</can>
    <can offset="u" same_as="foo.com" id="foo 02">foo 02</can>
    <can update="x" site="merge-xml-02" site_id="bar.com" xmltv_id="bar@com">bar@com</can>
    <can offset="u" same_as="bar.com" id="bar 01">bar 01</can>
    <can update="x" site="merge-xml-03" site_id="xxx.com" xmltv_id="xxx@com">xxx@com</can>
    <can offset="u" same_as="xxx.com" id="xxx 01">xxx 01</can>
    <can offset="u" same_as="xxx.com" id="xxx 02">xxx 02</can>
    <can offset="u" same_as="xxx.com" id="xxx 03">xxx 03</can>
    

    【讨论】:

    • 我试试,真的很感谢你的帮助,当你在米兰的时候,你有一小撮啤酒的报酬!
    • @Tapiocapioca 我在西伯利亚中部,但我希望有时能去那里:)
    • 我希望我能和我的女朋友一起去西伯利亚 :) 但也许你更喜欢伏特加 :P 我正在工作,但忽略了最后一场比赛。可以是什么?我的结果是: foo@comfoo 01foo 02bar@combar 01
    【解决方案4】:

    这可能对你有用(GNU sed):

    sed 's#.*same_as=\("[^"]*"\).*#/site_id=\1/a&#' file2 | sed -f - file1
    

    将 file2 转换为 sed 脚本,该脚本在将 same_as 的值与 file1 的 site_id 匹配时附加每一行。然后将生成的脚本通过管道传递给对 file1 运行的第二次 sed 调用。每次读入 file1 中的一行时,file2 中的行都会依次附加到它上面。

    要从 file1 中删除与 file2 不匹配的行,请使用:

    sed -e 's#.*same_as=\("[^"]*"\).*#/site_id=\1/{a&\nx;s/^/x/;x}#' file2 |
    sed -f - -e 'x;/x/{z;x;b};d' file1
    

    这会在保留空间中添加一个标志,该标志在添加来自 file2 的行时设置,如果未设置,则从 file1 中删除当前记录

    【讨论】:

    • 非常感谢您的帮助,您的 seggestion 也运行得非常好! :) :)
    • 我想问你,是否可以不加入第一个文件,如果没有匹配?通过这种方式,第一个文件中的所有行都被连接了,但是如果没有第二行,我就无法使用它们。
    • 还给你一小撮啤酒和在米兰支付的比萨饼 :)
    猜你喜欢
    • 2013-04-29
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 2013-07-10
    相关资源
    最近更新 更多