1

我有两个文件,我想将 file1 划分为等于 file2 中的行数的部分。

这里将 file2 中的每一行与 file1 进行比较,并将 file1 中的所有匹配记录形成为新文件。

文件 1

  <AUDIT_RECORD TIMESTAMP="2013-08-26T19:31:17" NAME="Query" CONNECTION_ID="21974096" STATUS="0" SQLTEXT="SHOW COLLATION"/> 
  <AUDIT_RECORD TIMESTAMP="2013-08-26T19:31:17" NAME="Query" CONNECTION_ID="21974099" STATUS="0" SQLTEXT="SHOW TABLES"/> 
  <AUDIT_RECORD TIMESTAMP="2013-08-26T19:31:17" NAME="Query" CONNECTION_ID="21974095" STATUS="0" SQLTEXT="SHOW COLLATION"/> 
  <AUDIT_RECORD TIMESTAMP="2013-08-26T19:31:17" NAME="Query" CONNECTION_ID="21974094" STATUS="0" SQLTEXT="SHOW COLLATION"/> 
  <AUDIT_RECORD TIMESTAMP="2013-08-26T19:31:17" NAME="Query" CONNECTION_ID="21974099" STATUS="0" SQLTEXT="SHOW COLLATION"/> 
  <AUDIT_RECORD TIMESTAMP="2013-08-26T19:31:17" NAME="Query" CONNECTION_ID="21974094" STATUS="0" SQLTEXT="SET NAMES utf8"/> 

文件2

21974096
21974100
21974095
21974094
21974099

所需输出:

21974094.txt

==========================================
TIMESTAMP="2013-08-26T19:31:17"
SQLTEXT="SET NAMES utf8"

==========================================
TIMESTAMP="2013-08-26T19:31:17"
SQLTEXT="SHOW COLLATION"


21974099.txt

==========================================
TIMESTAMP="2013-08-26T19:31:17"
SQLTEXT="SHOW COLLATION"

==========================================
TIMESTAMP="2013-08-26T19:31:17"
SQLTEXT="SHOW TABLES"


21974095.txt

==========================================
TIMESTAMP="2013-08-26T19:31:17"
SQLTEXT="SHOW COLLATION"

...

为了用 awk 实现这一点,我编写了如下代码,但它不能满足我的要求。

awk 'NR==FNR{a[$4];next}!($4 in a){ print $2 "\n" $6 "\n=========\n" > $4 ".txt"}' file2  file1

任何人都可以帮助我如何使用 awk 或任何其他 shell 命令来实现上述要求。(它必须至少生成 10000 个文件,并且应该在最多 10 分钟内完成生成文件。)

第一次尝试

如果我已经执行了下面的命令,它几乎达到但不完全满足要求。

awk 'NR==FNR{a[$1];next}{split($4,b,"\"")}(b[2] in a){print $2"\n"$10"\n=========\n" > b[2]".txt"}' file2 file1

来自文件之一的输出

TIMESTAMP="2013-08-26T19:57:34"
SQLTEXT="/*
=========

TIMESTAMP="2013-08-26T19:57:34"
SQLTEXT="/*
=========

TIMESTAMP="2013-08-26T19:57:34"
SQLTEXT="SHOW

但我想要如下所示的输出

TIMESTAMP="2013-08-26T19:57:34"
SQLTEXT="/*show variables"
=========

TIMESTAMP="2013-08-26T19:57:34"
SQLTEXT="/* select * from table "
=========

TIMESTAMP="2013-08-26T19:57:34"
SQLTEXT="SHOW collations "

意味着在这里我需要将文件 1 的分隔符指定为 '"',而文件 2 没有分隔符 ..

有人可以帮忙吗?

4

3 回答 3

3

您应该使用 split 函数将第四个单词按"字符分开,以便获得与 file2 中的值匹配的数字。你也应该a[$1]在第五块。

该脚本应该可以工作:

awk 'NR==FNR{a[$1];next}{split($4,b,"\"")}(b[2] in a){print $2"\n"$6"\n=========\n" > b[2]".txt"}' file2  file1

更新:

只要 file1 中没有多余的引号,我们就可以使用该"字符作为字段分隔符:

awk -F\" 'NR==FNR{a[$1];next}($6 in a){print "TIMESTAMP=\""$2"\"\nSQLTEXT=\""$10"\"\n=========\n" > $6".txt"}' file2  file1

"我们用字符作为分隔符分割输入文件,所以字段 $2 是时间戳,字段 $6 是 conn。id,提交 $10 是 SQLTEXT。

第一个块NR==FNR{a[$1];next}使用来自 file2 的连接 ID 填充数组(第一个文件的 NR == FNR)。我们过滤了($6 in a)第二个文件的行(因为我们在第一个块中调用了 next ),其连接 id 是 table 的索引a。如果我们找到匹配项,则{print "TIMESTAMP=\""$2"\"\nSQLTEXT=\""$10"\"\n=========\n" > $6".txt"}'执行该块,将相关信息打印到文件 conn_id.txt

于 2013-08-27T16:59:18.300 回答
2

这是我的解决方案:

#!/usr/bin/gawk -f

BEGIN {
    f = ARGV[2]
    while (getline id < f) {
        ids[id] = 0
    }
    ARGV[2] = ""
}

match($0, /.*<AUDIT_RECORD.* (TIMESTAMP="[^"]*").* CONNECTION_ID="([^"]*)".* (SQLTEXT="[^"]*").*/, a) {
    id = a[2]
    if (id in ids) {
        key = id "|" ids[id]++
        timestamps[key] = a[1]
        sqltexts[key] = a[3]
    }
}

END {
    for (id in ids) {
        count = ids[id]
        if (count) {
            file = id ".txt"
            for (i = 0; i < count; ++i) {
                key = id "|" i
                printf "%s\n%s\n%s\n\n", "==========================================", timestamps[key], sqltexts[key] > file
            }
            close(file)
        }
    }
}

运行它

gawk -f script.awk file1 file2

实际上,我更喜欢在进入第一个文件的循环之前预处理第二个文件,因为我不喜欢添加不必要的条件检查。

printf如果它不是您想要的确切输出,您也可以只进行修改。

实际上,在其他解决方案中,gawk 的匹配可以让一个人明确应该真正针对哪些参数,因此如果其他行的格式与其他额外的键/值对一样,上面的代码也可以工作。

更新

这个更简单,但根据条目的数量一次打开太多输出文件的风险。

#!/usr/bin/gawk -f

BEGIN {
    f = ARGV[2]
    while (getline id < f) {
        ids[id] = 0
    }
    ARGV[2] = ""
}

match($0, /.*<AUDIT_RECORD.* (TIMESTAMP="[^"]*").* CONNECTION_ID="([^"]*)".* (SQLTEXT="[^"]*").*/, a) {
    id = a[2]
    if (id in ids) {
        printf "%s\n%s\n%s\n\n", "==========================================", a[1], a[3] > id ".txt"
    }
}
于 2013-08-27T17:27:29.460 回答
2

这不使用awk但它有效:

while read -r n
do
    echo "Generating $n.txt"
    grep $n file1 | sed 's/^.*\(TIMESTAMP="[^"]\+"\).*\(SQLTEXT="[^"]\+"\).*$/=======================\n\1\n\2\n/' > $n.txt

    # If you don't want an empty file when there's no match, add this line
    if [ ! -s $n.txt ]; then rm -f $n.txt ; fi
done < file2
于 2013-08-27T16:52:29.143 回答