如何使用awk分隔和附加文本

时间:2016-07-14 21:29:56

标签: awk

专家,

我在xml文件中有以下文本(文件中有20,000行)。

 "21006041";"28006041";"34006211";"43";"101210-0001";101

以下是我需要每行的结果并附加到新文件的方法。

"

以下是我需要做的以获得上述结果。

  • 我用"
  • 替换了<record record_no = "1" error_code="
  • 删除 BEGIN { FS=OFS=";" } /<record/ { gsub(/&quot;/,"\"") gsub(/&apos;/,"") gsub(/.*="|">.*/,"",$1) $(NF+1)=$1; $1=""; print $0; }
  • 获取文本101(此位置可以有任何值)
  • 追加到最后。

这是我一直在尝试的。

foo

2 个答案:

答案 0 :(得分:1)

这应该可以解决问题。

awk -F'">' -v OFS=';' '{gsub(/<record record_no = \"[0-9]+\" error_code="/,""); gsub(/&quot;/,"\""); print $2,$1}'

策略是:

  1. 将字符串拆分为xml元素">
  2. 的结束字符
  3. 删除xml元素的第一位,包括属性名称,只留下错误代码。
  4. 将所有&quot;个xml实体替换为"
  5. 以相反的顺序打印两个FS部分。
  6. 使用以下数据生成脚本进行测试。该脚本将生成500x20000行文件,其中包含随机长度的记录,其中一些在值中带有破折号。

    #!/bin/bash
    recCount=0
    for h in {1..500};
    do
        for i in {1..20000};
        do
            ((recCount++))
            error=$(( RANDOM % 998 + 1 ))
            record="<record record_no = "'"'"${recCount}"'"'" error_code="'"'"${error}"'"'">"
            upperBound=$(( RANDOM % 4 + 5 ))
            for (( k=0; k<${upperBound}; k++ ));
            do
                randomVal=$(( RANDOM % 99999999 + 1))
                record+="&quot;${randomVal}"
                if [[ $((RANDOM % 4)) == 0 ]];
                then
                    randomVal=$(( RANDOM % 99999999 + 1))
                    record+="-${randomVal}"
                fi    
                record+="&quot;"
                if [[ $k != $(( ${upperBound} - 1 )) ]];
                then
                    record+=";"
                fi    
            done;
            echo "${record}" >> "file-${h}.txt"
        done;
    done;
    

    在我的笔记本电脑上,我获得了以下表现。

    $ time cat file-*.txt | awk -F'">' -v OFS=';' '{gsub(/<record record_no = \"[0-9]+\" error_code="/,""); gsub(/&quot;/,"\""); print $2,$1}' > result
    
    real    0m18.985s
    user    0m17.673s
    sys 0m2.697s
    

    作为额外的奖励,这里是sed中的“等效”命令: sed -e 's|\(&quot;\)|"|g' -e 's|^.*error_code="\([^>]\+\)">\(.\+\).*$|\2;\1|g'

    尽管策略相同,但速度要慢得多。使用了两个表达式。首先用&quot;替换所有" xml实体。最后将>之后的所有字符(。+)分组。以相反的顺序\2;\1

    显示记住的模式

    时间统计:

    $ time cat file-* | sed -e 's|\(&quot;\)|"|g' -e 's|^.*error_code="\([^>]\+\)">\(.\+\).*$|\2;\1|g' > result.sed
    
    real    5m59.576s
    user    5m56.136s
    sys 0m9.850s
    

答案 1 :(得分:0)

这太厚了:

$ awk -F"&quot;+" -v OFS='";"' -v dq='"' '{gsub(/^.*="|">$/,"",$1);print dq""$2,$4,$6,$8,$10dq";"$1}' test.in
"21006041";"28006041";"34006211";"43";"101210-0001";101