Awk:将孤立的文本合并到上面的特定字段中

时间:2012-10-27 01:47:50

标签: sed awk

给定一个包含项目信息的制表符分隔的文本文件:

41850   0.4     0.5     LG      EN      RP      Billy Makes a  Fridgewell, Norm 
Friend       
9338    0.4     0.5     LG      EN      RP      Shine, The Musical!     Mustard, Colonel   
7255    0.5     0.5     LG      EN      RP      Can You Play the   Truman, Harriet
Jew's Harp 
9314    0.5     0.5     LG      EN      RP      Hi, Skippy      Plum, Prof   

注意其中两行的“孤立”标题。使用Awk,我如何将这个孤儿合并回上面的标题字段?

伪AWK:

awk '/^[[:digit:]]/{getline; ??? 
    if next line ~ /^[[:alpha:]]/ title=$7 + previous
    END{print $0}' <FILE

无论如何,步骤似乎是:

要么

  • 找到“正常”行,
  • 测试以下行是否为“orphan”
  • 如果是,请将“孤儿”附加到字段7 [标题字段],
  • 打印行

  • 查找“孤儿”
  • 以某种方式附加到前一行的字段7 [永远不会有两个连续的孤儿]

第一种方式对我来说似乎最容易 - 但是,那时候,我就是无知的人。

3 个答案:

答案 0 :(得分:2)

$ tac file | awk 'BEGIN{FS=OFS="\t"} NF==1{s=" "$0;next} {$7=$7 s; s=""}1' | tac
41850   0.4     0.5     LG      EN      RP      Billy Makes a Friend    Fridgewell, Norm
9338    0.4     0.5     LG      EN      RP      Shine, The Musical!     Mustard, Colonel
7255    0.5     0.5     LG      EN      RP      Can You Play the Jew's Harp     Truman, Harriet
9314    0.5     0.5     LG      EN      RP      Hi, Skippy      Plum, Prof

这是一种没有tac并使用GNU awk的替代方法(只需将gensub()替换为2个sub()调用或者match()或者如果你不想使用gawk那样的话:

$ cat tst.awk
BEGIN { FS="\t" }
NF==1 { s = gensub(/([^\t]+[\t]){6}[^\t]+/, "\\0 "$1, "", s); next }
      { printf "%s",s; s=$0 ORS }
END   { printf "%s",s }

$ gawk -f tst.awk file
41850   0.4     0.5     LG      EN      RP      Billy Makes a Friend    Fridgewell, Norm
9338    0.4     0.5     LG      EN      RP      Shine, The Musical!     Mustard, Colonel
7255    0.5     0.5     LG      EN      RP      Can You Play the Jew's Harp     Truman, Harriet
9314    0.5     0.5     LG      EN      RP      Hi, Skippy      Plum, Prof

答案 1 :(得分:2)

这可能适合你(GNU sed):

sed '$!N;/\n\([^\t]*\t\)\{7\}/!s/\(\t[^\t]*\)\n\(.*\)/ \2\1/;P;D' file

答案 2 :(得分:1)

我意识到问题被标记为awk,但这可能是Perl更容易的时候之一:

perl -F"\t"  -lane 'BEGIN { $, = "\t" } 
            if (/^\d{2}/) { print @saved if @saved; @saved = @F } 
                     else { $saved[6].=" $_" }; 
                      END { print @saved }' foo.txt 

虽然这是同一个想法的awk版本(通过Ed Morton进行了一些改进):

awk -F"\t" '/^[0-9][0-9]/  { if (prefix) { print prefix"\t"title"\t"suffix }
                             prefix=$1
                             for ( i=2; i<=6; ++i ) prefix=prefix"\t"$i
                             title=$7; suffix=$8
                             next } 
                           { title = title" "$0 } 
                       END { print prefix"\t"title"\t"suffix }' foo.txt 

这两个脚本都给我这个输出,看起来像你想要的那样:

41850   0.4     0.5     LG      EN      RP      Billy Makes a Friend    Fridgewell, Norm 
9338    0.4     0.5     LG      EN      RP      Shine, The Musical!     Mustard, Colonel
7255    0.5     0.5     LG      EN      RP      Can You Play the Jew's Harp     Truman, Harriet
9314    0.5     0.5     LG      EN      RP      Hi, Skippy      Plum, Prof