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

Sed Awk:将孤立文本合并到上面一行中的特定字段,sed,awk,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 R

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

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 41850 0.4 0.5 LG EN RP比利制作冰箱,标准 朋友 9338 0.4 0.5 LG EN RP闪亮,音乐剧!芥末,上校 7255 0.5 0.5 LG EN RP你能扮演杜鲁门吗,哈里特 犹太竖琴 9314 0.5 0.5 LG EN RP Hi,跳跃李子,教授 请注意其中两行上的“孤立”标题。使用Awk,如何将此孤立项合并回上面的标题字段

伪awk:

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

结束{print$0}'我意识到问题被标记为
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
,但这可能是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进行了一些改进):

这里有一种不使用tac并使用GNU awk的替代方法(如果不想使用gawk,只需将gensub()替换为2个sub()调用或match()或其他任何调用):

这里有一种不使用tac并使用GNU awk的替代方法(如果不想使用gawk,只需将gensub()替换为2个sub()调用或match()或其他任何调用):

这可能适用于您(GNU-sed):

这可能适用于您(GNU-sed):



这太棒了!!我会做一些测试…看起来这是大获全胜!这一次,perl更容易让人眼前一亮。使用它!谢谢!但这并不是你真正想用awk解决问题的任何方法。这太棒了!!我会做一些测试…看起来这是大获全胜!这一次,perl更容易让人眼前一亮。使用它!谢谢!这一点但是,这并不是你真正想用awk解决问题的任何方法。+1-使用tac是一个可爱的技巧,它确实简化了awk代码。在你对我答案的评论中,你说了“任何方法”-那么其他的是什么呢?另外两个明显的方法是将记录保存在数组中,并在结尾部分对其进行处理,或者保存当前行,直到下一行被读取,然后在适当的情况下更改$7后打印它,这就是你要做的,它只是使用所有这些单独的变量并对第二部分的条件求反而不是使用next和所有这些空语句(尾随分号)Markreed:我发布了一个不使用tac的替代方案,这样你就可以明白我的意思了。谢谢你的改进,@EdMorton。我从来没有深入到awk中-我从尽可能使用ksh内置程序到使用Perl,中间没有太多时间。:)我去掉了多余的半部分,转而使用<代码>接下来
。我考虑使用一个数组而不是单独的变量;如果awk有办法在一个数组中获取所有字段,并一次性将它们复制到另一个数组中,我会这样做……awk是关于保持语言小而简单,这样就不会有语言结构来做其他语言结构所做的琐碎事情。要将数组a复制到数组b,只需执行“for(a中的i)b[i]=a[i]”,因此文字赋值仍然只是针对数字和字符串,但对于数组来说,这是一个微不足道的“do-do”赋值。+1-使用tac是一个可爱的技巧,它绝对简化了awk代码。在你对我的答案的评论中,你说“任何方式”"-那么其他的是什么呢?另外两个明显的方法是将记录保存在数组中,并在结尾部分对其进行处理,或者保存当前行,直到下一行被读取,然后在适当的情况下更改$7后打印它,这就是你要做的,它只是使用所有这些单独的变量并对第二部分的条件求反而不是使用next和所有这些空语句(尾随分号)Markreed:我发布了一个不使用tac的替代方案,这样你就可以明白我的意思了。谢谢你的改进,@EdMorton。我从来没有深入到awk中-我从尽可能使用ksh内置程序到使用Perl,中间没有太多时间。:)我去掉了多余的半部分,转而使用<代码>接下来。我考虑使用一个数组而不是单独的变量;如果awk有办法在一个数组中获取所有字段,并一次性将它们复制到另一个数组中,我会这样做……awk是关于保持语言小而简单,这样就不会有语言结构来做其他语言结构所做的琐碎事情。若要将数组a复制到数组b,只需执行“for(a中的i)b[i]=a[i]”操作,所以文字赋值仍然只是针对数字和字符串,但执行起来很简单数组的赋值。孤立字段需要插入到前一行的正确位置,而不仅仅是追加到结尾。孤立字段需要插入到前一行的正确位置,而不仅仅是追加到结尾。
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 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
$ 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
sed '$!N;/\n\([^\t]*\t\)\{7\}/!s/\(\t[^\t]*\)\n\(.*\)/ \2\1/;P;D' file