Bash,Awk,Sed?在文件中查找字符串并在字符串中追加数字?

时间:2016-10-09 16:17:56

标签: bash loops awk sed

我希望逐行搜索大型文本文件,并找到包含" N:;;"的每个条目。只需将其更改为" N:07401000000;;"然后下一次出现" N:;;"将更改为" N:07401000002;;"等完整的条目文件。以下是之前和之后的示例。

在:

BEGIN:VCARD
VERSION:2.1
N:;;
TEL;TYPE=CELLVOICE:07401000000
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:;;
TEL;TYPE=CELLVOICE:07401000001
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:;;
TEL;TYPE=CELLVOICE:07401000002
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:;;
TEL;TYPE=CELLVOICE:07401000003
END:VCARD

结果看起来像这样:

BEGIN:VCARD
VERSION:2.1
N:07401000000;;
TEL;TYPE=CELLVOICE:07401000000
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:07401000001;;
TEL;TYPE=CELLVOICE:07401000001
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:07401000002;;
TEL;TYPE=CELLVOICE:07401000002
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:07401000003;;
TEL;TYPE=CELLVOICE:07401000003
END:VCARD

任何帮助或想法都会很棒。

  

您是否希望N值以硬编码值开始并递增或仅从后续CELLVOICE复制值?

实际上这是一个好主意。如何在CELLVOICE中提到的价值。

3 个答案:

答案 0 :(得分:2)

这是实现您想要的最强大,最易于扩展的方式:

$ cat tst.awk
BEGIN { RS="END:VCARD\\s*"; FS="\n"; OFS=":" }
{
    $0 = $0 gensub(/\s+$/,"",1,RT)

    for (i=1; i<=NF; i++) {
        name = gensub(/:.*/,"",1,$i)
        value = gensub(/.*:/,"",1,$i)
        n2v[name] = value
        names[i] = name
    }

    n2v["N"] = n2v["TEL;TYPE=CELLVOICE"] n2v["N"]

    for (i=1; i<=NF; i++) {
        name  = names[i]
        value = n2v[name]
        print name, value
    }
}

$ awk -f tst.awk file
BEGIN:VCARD
VERSION:2.1
N:07401000000;;
TEL;TYPE=CELLVOICE:07401000000
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:07401000001;;
TEL;TYPE=CELLVOICE:07401000001
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:07401000002;;
TEL;TYPE=CELLVOICE:07401000002
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:07401000003;;
TEL;TYPE=CELLVOICE:07401000003
END:VCARD

上面使用GNU awk表示gensub(),多字符RSRT,基本(和惯用)的想法是将输入拆分为以{{结尾的记录1}}并且对于每个记录首先创建一个数组(END:VCARD),它将字段名称(每行上第一个n2v[]之前的部分)映射到它们的值(第一个{{1}之后的部分})然后你可以通过它的名字操纵每个字段,这样你就可以轻松地改变数值,重新排列顺序,填写默认值等等。

答案 1 :(得分:0)

Ed Morton的答案是全面的,但是如果你正在寻找快速解决方案,那么这也可以完成这项工作:

$ awk 'BEGIN {N=07401000000} /N:;;/ {print "N:"N++";;"; next} 1' myfile.vcf

答案 2 :(得分:0)

假设N:;;CELLVOICE的行彼此相邻,如示例所示,这里是一个sed

的解决方案
$ sed -E '/N:;;/{N;s/.*\n(.*CELLVOICE:([0-9]+))/N:\2;;\n\1/}' ip.txt 
BEGIN:VCARD
VERSION:2.1
N:07401000000;;
TEL;TYPE=CELLVOICE:07401000000
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:07401000001;;
TEL;TYPE=CELLVOICE:07401000001
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:07401000002;;
TEL;TYPE=CELLVOICE:07401000002
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:07401000003;;
TEL;TYPE=CELLVOICE:07401000003
END:VCARD
  • 如果模式/N:;;/匹配,请使用N
  • 获取下一行
  • 然后按照要求的格式执行替换,\n分隔两行


使用perl的解决方案,将整个输入文件作为一个大字符串,然后执行替换

perl -0777 -pe 's/N:;;\n(.*CELLVOICE:(\d+))/N:$2;;\n$1/g' ip.txt