匹配以下行中的单词后提取随机模式

时间:2012-10-15 08:25:49

标签: unix sed awk

提取与关键字对应的家庭数据。

Z1/NEW "THE_PALM" 769 121003   1545     
NEW HOUSE IN
SOMETHING SOMETHING

SN                HOUSE            CLASS
FIRST             PSD93_PU         1579

CHAIRS
WOOD
SILVER SPOON
GREEN GARDEN



Z1/OLD "THE_ROSE" 786 121003   1343     
NEW HOUSE OUT
SOMETHING NEW

SN                HOUSE            CLASS
FIRST_O           PSD1000_ST       1432

CHAIRS
WOOD
GREEN GARDEN
BLACK PAINT


Z1/OLD "The_PURE" 126 121003   3097    
NEW HOUSE IN
SOMETHING OLD

SN                HOUSE            CLASS
LAST_O            JD4_GOLD         1076

CHAIRS
SILVER SPOON

我有一个非常大的文件。每个描述的末尾都有关于房子的项目清单。对应于包含SILVER SPOON的房屋,我想提取HOUSE ID,如数据PSD93_PU和日期121003。我尝试了以下方法:

awk 'c-->0;$0~s{if(b)for(c=b+1;c>1;c--)print r[(NR-c+1)%b];print;c=a}b{r[NR%b]=$0}' b=7 a=0 s="SILVER" infile > outfile

但问题是关键字SILVER上方的行数是如此随机,我无法找出解决方案。

3 个答案:

答案 0 :(得分:0)

假设每个新房子都以Z1

开头
 $ awk '$1 ~ /^Z1/ { date=$4; id=""; f=0; next; } \
        $1 == "SN" { f=1; next; }                 \
        f == 1 { id=$2; f=0; next; }              \
        $1" "$2 == "SILVER SPOON" { print id,date }' file 

,在新房子上,重置所有变量并获取日期 如果 SN 匹配,则下一行包含id 从该行获取id 如果找到“ SILVER SPOON ”,则打印iddate 如果没有找到,将会满足新房子,并重置变量。

使用给定数据进行测试:

$ awk '$1 ~ /^Z1/ { date=$4; id=""; f=0; next; } $1 == "SN" { f=1; next; } f == 1 { id=$2; f=0; next; } $1 == "SILVER SPOON" && $2 == "SPOON" { print id,date }' file 
PSD93_PU 121003
JD4_GOLD 121003

note : 如果有人知道如何以及$1 == "SILVER" && $2 == "SPOON"可以在一个声明中合并在一起,那就好了:) - 如:$1,$2 == "SILVER SPOON"

修改的: 可以使用$1" "$2 == "SILVER SPOON"来完成 一个人可能会省略空格并执行$1$2 == "SILVERSPOON"但即使$2为空并且$1包含整个字符串,或$1 SILVERSPO $2 ON 。所以这个空间就像是一场严格的匹配。

答案 1 :(得分:0)

使用sed:

sed -n -e 's/^Z1[^"]*"[^"]*"[ \t]*[0-9]*[ \t]*\([0-9]*\).*/\1/p'
       -e '/^SN[ \t]*HOUSE/ { n; s/^[^ \t]*[ \t]*\([^ \t]*\).*/\1/p }'

首先,我们使用sed选项调用-n,以告诉它只打印我们告诉它的内容。

第一个命令将搜索特定模式以提取日期。该模式包括:

  1. ^Z1:以字符串“Z1”开头的行。
  2. [^"]*:零个或多个不是双引号的字符
  3. ":双引号字符
  4. [^"]*:零个或多个不是双引号的字符
  5. [ \t]*:零个或多个字符为制表符或空格
  6. [0-9]*:零个或多个数字
  7. [ \t]*:零个或多个字符为制表符或空格
  8. \([0-9]*\):零个或多个数字。使用反斜括号来捕获匹配,即。匹配存储在辅助变量\1中。
  9. .*:零个或多个字符,有效地跳过所有字符,直到该行结束。
  10. 然后将此匹配的行替换为\1,其中包含我们捕获的内容:日期。命令后p告诉sed打印结果。

    第二行包含两个组合在一起的命令(在大括号内),因此它们仅在大括号之前的“地址”上执行。地址是一种模式,因此它在与模式匹配的每一行上执行。该模式由一行以“SN”开头,后跟一系列空格或制表符,后跟字符串“HOUSE”。

    当模式匹配时,我们首先执行n next命令,该命令从输入加载下一行。然后,我们从新行中提取ID,其方式类似于提取日期。匹配的替代模式是:

    1. ^[^ \t]*:以零个或多个不是空格或制表符(空格)的字符开头的字符串。
    2. [ \t]*:然后有一个零或多个空格和/或制表符的序列。
    3. \([^ \t]*\):然后捕获一系列非空白字符
    4. .*:匹配剩余的字符,以便跳过它们。
    5. 替换成为捕获的ID,我们再次告诉sed将其打印出来。

      这将打印出包含日期的行,后面是包含ID的行。如果你想要一个格式为ID date的行,你可以将sed的输出传递给另一个sed实例,如下所示:

      sed -n -e [...] | sed -e 'h;n;G;s/\n/ /'
      

      此sed实例执行以下操作:

      1. 读取一行,h命令告诉它将该行存储到保留空间(辅助缓冲区)。
      2. 使用n命令阅读下一行。
      3. G get命令会将保留空间的内容追加到模式空间(工作缓冲区)中,所以现在我们有ID行后跟日期行。
      4. 最后,我们用空格替换换行符,因此这些行连接成一行。
      5. 希望这有助于=)

答案 2 :(得分:0)

如果您的记录被两个或三个空白行分隔,并且家庭项目之前的行间距一致,您可以使用GNU awk,如下所示:

awk -r 'BEGIN { RS="\n{3}\n*"; FS="\n" } /SILVER SPOON/ { split($1, one, OFS); split($6, two, OFS); print two[2], one[4] }' file.txt

结果:

PSD93_PU 121003
JD4_GOLD 121003