期望的

期望的

我有一个数据文件,日期在第二列

# cat datafile
-;20210106;-;-;-;
-;20210112;-;-;-;
-;20210112;-;-;-;
-;20210112;-;-;-;
...
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210219;-;-;-;
-;20210219;-;-;-;
-;20210221;-;-;*20210219*;

连字符“ -”代表随机文本数据,点“ ...”代表更多行数据,“*”代表同一列中的随机文本。我想要的只是基于第二列之间的20210112数据20210219

我想避免,sed/grep因为两者也会在其他列中 grep 类似的模式。

# sed -n '/20210112/,/20210219/p' datafile
-;20210112;-;-;-;
-;20210112;-;-;-;
-;20210112;-;-;-;
...
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210219;-;-;-;
-;20210219;-;-;-;
-;20210221;-;-;*20210219*;

它也会匹配其他不相关行中的一些其他文本。所以,我猜 AWK 是一个更好的候选者,但我注意到 awk 仅在第一个模式的第一个匹配到第二个模式的第一个匹配之间打印

# awk -F';' '$2 ~ /20210112/,$2 ~ /20210219/' datafile
-;20210112;-;-;-;
-;20210112;-;-;-;
-;20210112;-;-;-;
...
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210219;-;-;-;

然而,我想将所有行带到第二个模式的最后一场比赛。

期望的

-;20210112;-;-;-;
-;20210112;-;-;-;
-;20210112;-;-;-;
...
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210219;-;-;-;
-;20210219;-;-;-;

答案1

我就是这样做的:

BEGIN {FS = ";"}

$2 == 20210112 {capture = 1}
capture == 1   {buffer = buffer $0 "\n"}
$2 == 20210219 {printf ("%s", buffer); buffer = ""}

在看到第一个模式第一次出现后,它开始将行放入缓冲区。对于第二个模式的每次出现,它都会打印缓冲区,并再次将缓冲区重置为空字符串。

答案2

如果我们忽略该...行并假设所有日期都按 2 美元的递增顺序排列(如示例所示),那么您所需要的只是:

$ awk -F';' '(20210112 <= $2) && ($2 <= 20210219)' file
-;20210112;-;-;-;
-;20210112;-;-;-;
-;20210112;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210219;-;-;-;
-;20210219;-;-;-;

或者更有效,因为一旦超过范围它就会退出:

$ awk -F';' '20210112 <= $2{f=1} $2 > 20210219{exit} f' file
-;20210112;-;-;-;
-;20210112;-;-;-;
-;20210112;-;-;-;
...
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210219;-;-;-;
-;20210219;-;-;-;

上面还假设如果输入中不存在结束日期,则您希望从开始日期打印到文件末尾,如果开始日期不存在,则您希望从大于开始日期的第一个日期开始打印到结束日期等

答案3

确定何时最后的已经看到模式的出现通常需要记住之前的行,并且只有在确定模式不再出现时才输出它们将要可见。

为了避免手动执行此操作,您可以截断文件的开头,反转它,截断文件的新开头,然后再次反转:

awk -F\; '$2 == 20210112,0' | tac | awk -F\; '$2 == 20210219,0' | tac

答案4

您可以在 中完成awk,您只需要稍微复杂一点的方法。请注意使用==代替~,这是为了避免匹配字段包含2021011220210219作为子字符串的情况(例如20210219123):

$ awk -F';' '$2==20210112{a=1}; $2==20210219 && a{b=1} a && b && $2!=20210219{exit}; a ' datafile 
-;20210112;-;-;-;
-;20210112;-;-;-;
-;20210112;-;-;-;
...
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210217;-;-;-;
-;20210219;-;-;-;
-;20210219;-;-;-;

或者,更详细但更容易理解:

$ awk -F';' '{
              if($2==20210112){ a=1 }
              if($2==20210219 && a){ b=1 } 
              if(a && b && $2!=20210219){ exit }; 
              if(a){ print }
             }' datafile 

或者,只需进行数值比较:

awk -F';' '$2>=20210112 && $2<=20210219' datafile 

顺便说一句,sed如果有必要,您仍然可以使用类似的东西,只需锚定模式,使其仅在第二个字段中匹配:

$ sed -n '/^[^;]*;20210112/,/^[^;]*;20210219/p' datafile

在这种情况下没有用,因为它将在第一个匹配处停止,但至少它不会在其他字段上匹配。

相关内容