-1

我有 2 个文件需要根据给定的模式(在本例中为电子邮件地址)合并。
如果可能的话,我想用 grep/sed 来做这件事。请解释答案,以便我弱小的大脑可以处理它。

新信息:没有现场地图。这些文件来自 2 个不同的数据源,并且行数并不总是相同。这是现实世界:当 Bob 停止更新他的博物馆会员资格时,他将不再列在文件 2 中。这是大型非营利组织会员状态每周报告的一部分。文件 1 将一直增长到年底,文件 2 可能会缩小或增长。

我已经将第二个文件设置为始终以逗号分隔的位置,并且第一个字段将始终是电子邮件地址,就像文件 1 中一样。

在文件 1 中有这样一行:

007@some.org,007,/Members/Inactive/Delete,2013-06-07T04:41:56.000Z,Never

在文件 2 中,有这样一行:

User 007@some.org:  Forward To:None  Enabled:false  Action:KEEP

我希望将文件 2 中的内容添加到文件 1 以创建格式如下的文件 3:

007@some.org,007,/Members/Inactive/Delete,2013-06-07T04:41:56.000Z,Never,Forward to:None,Enabled:false,Action:KEEP

3 个新列应始终添加到行尾。

4

3 回答 3

1

首先使用搜索和替换以所需格式(逗号分隔)修改 file2。在这里,我正在使用perl它来实现这一点。sed也可以使用

perl -pe 's/User\s+(\S+):\s+(.*?:\S+)\s+(.*?:\S+)\s+(.*?\S+)/\1,\2,\3,\4/g' file2 > file2_new

这将导致:

$ cat file2_new
007@some.org,Forward To:None,Enabled:false,Action:KEEP

然后只需使用joinwith 分隔符,连接两个文件

join -t , file1 file2_new

输出:

007@some.org,007,/Members/Inactive/Delete,2013-06-07T04:41:56.000Z,Never,Forward To:None,Enabled:false,Action:KEEP
于 2013-09-27T19:58:48.383 回答
1

使用GNU awk (for )的较新版本 (for \sand\S而不是[[:space:]]and ):[^[:space:]]gensub()

$ cat tst2.awk
BEGIN {re="\\S+\\s+([^:]+):\\s+([^:]+:\\S+)\\s+(\\S+)\\s+(\\S+).*"; FS=OFS=","}
NR==FNR {map[gensub(re,"\\1","")] = gensub(re,"\\2,\\3,\\4",""); next}
{print $0, map[$1]}
$
$ cat file1
007@some.org,007,/Members/Inactive/Delete,2013-06-07T04:41:56.000Z,Never
$
$ cat file2
User 007@some.org:  Forward To:None  Enabled:false  Action:KEEP
$
$ awk -f tst2.awk file2 file1
007@some.org,007,/Members/Inactive/Delete,2013-06-07T04:41:56.000Z,Never,Forward To:None,Enabled:false,Action:KEEP

或使用任何现代 awk:

$ cat tst.awk
BEGIN{ FS=OFS="," }
NR==FNR {
    email = $0
    gsub(/^[^[:space:]]+[[:space:]]+|:.*/,"",email)

    sub(/^[^:]+:[[:space:]]*/,"")

    rec = ""
    while ( match($0,/[^:]+:[^:[:space:]]+/) > 0 ) {
        rec = rec (rec ? OFS : "") substr($0,RSTART,RLENGTH)
        $0 = substr($0,RSTART+RLENGTH+1)
        sub(/^[[:space:]]+/,"",$0)
    }

    map[email] = rec
    next
}

{ print $0, map[$1] }
$
$ cat file1
007@some.org,007,/Members/Inactive/Delete,2013-06-07T04:41:56.000Z,Never
$
$ cat file2
User 007@some.org:  Forward To:None  Enabled:false  Action:KEEP
$
$ awk -f tst.awk file2 file1
007@some.org,007,/Members/Inactive/Delete,2013-06-07T04:41:56.000Z,Never,Forward To:None,Enabled:false,Action:KEEP
于 2013-09-27T20:08:16.630 回答
0

我之前建议加入评论,而不注意输入和输出格式。正如 EdMorton 指出的,即使对输入文件进行了排序,这也不能仅在 join 中完成。因此,在与 EdMorton 讨论后,我实际上详细讨论了这个问题,这是我目前的解决方案,假设第二个文件是 TAB 分隔的:

sed -re 's/^User\s//' -e 's/:/,/' file2 | join -t , file1 - | sed -re 's/\t/,/g' -e 's/,,/,/'

上面的命令在我的 cygwin/win7 环境下工作,如果你的 shell 或 file2 分隔符不同,你可能需要稍微玩一下。

一些解释:

sed -re 's/^User\s//' -e 's/:/,/' file2

删除前导“用户”并将第一次出现的冒号更改为逗号,这使得 file2 可以与带有逗号分隔符的 file2 连接。

sed -re 's/\t/,/g' -e 's/,,/,/'

根据最终格式的要求,用逗号替换分隔符。因为 join 会在 file1 和 file2 之间的输出中添加一个分隔符,所以我们会看到一对没有最后替换的逗号。

这是输出:

加入结果

于 2013-09-27T20:43:02.337 回答