0

Extract household data corresponding to a keyword.

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

I have a very large sized file. There is a list of items about the house at the end of every description. Corresponding to the houses containing SILVER SPOON, I want to extract the HOUSE ID as in data PSD93_PU and date 121003. I tried the following:

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

But the problem is that the number of lines above the keyword SILVER are so random, that I can't figure out the solution.

4

3 回答 3

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. .*: 零个或多个字符,有效地跳过所有字符直到行尾。

然后将匹配的行替换为\1,其中包含我们捕获的内容:日期。pafter 命令告诉 sed 打印结果。

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

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

  1. ^[^ \t]*: 以零个或多个不是空格或制表符(空白)的字符开头的字符串。
  2. [ \t]*: 然后有零个或多个空格和/或制表符的序列。
  3. \([^ \t]*\):然后捕获一系列非空白字符
  4. .*: 匹配剩余的字符以便跳过它们。

替换成为捕获的 ID,我们再次告诉 sed 将其打印出来。

这将打印出包含日期的行,然后是包含 ID 的行。如果您想要格式中的一行ID date,您可以将 sed 的输出通过管道传输到另一个 sed 实例中,如下所示:

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

此 sed 实例执行以下操作:

  1. 读取一行,h命令告诉它将该行存储到保持空间(辅助缓冲区)中。
  2. 使用命令阅读下一行n
  3. get 命令会将保持空间的G内容附加到模式空间(工作缓冲区)中,所以现在我们有了 ID 行和日期行。
  4. 最后,我们将换行符替换为空格,因此这些行合并为一行。

希望这会有所帮助=)

于 2012-10-15T11:10:27.447 回答
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
于 2012-10-15T12:38:06.503 回答
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”,则从该行获取打印, 如果找不到,则打印新房子将满足并重置变量。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

注意:如果有人知道如何以及是否$1 == "SILVER" && $2 == "SPOON"可以在一个很好的语句中合并在一起:) - 比如:$1,$2 == "SILVER SPOON"

编辑:可以用$1" "$2 == "SILVER SPOON".
一个人可能会省略空格并做$1$2 == "SILVERSPOON",但即使$2是空的并且$1包含整个字符串,或者$1SILVERSPO并且$2ON ,它也会匹配。因此,空间在充当严格匹配。

于 2012-10-15T09:36:12.317 回答