Text-Processing

使用 AWK 在第一個模式的第一次出現到第二個模式的最後一次出現之間列印行

  • November 15, 2021

我有一個數據文件,日期在第二列

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

連字元“ -”代表隨機文本數據,點“ ...”代表多行數據,“*”代表同一列中的隨機文本。我想要的只是基於第二列的20210112&之間的數據。20210219

我想避免sed/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;-;-;-;

如果我們忽略該...行並假設您的所有日期都在增加 $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;-;-;-;

以上還假設如果輸入中沒有結束日期,那麼您希望從開始日期列印到文件末尾,如果開始日期不存在,那麼您希望從大於開始日期的第一個日期開始列印到結束日期等

我會這樣做:

BEGIN {FS = ";"}

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

在看到第一個模式的第一次出現後,它開始將行放入緩衝區。對於第二個模式的每次出現,它都會列印緩衝區,並再次將緩衝區重置為空字元串。

引用自:https://unix.stackexchange.com/questions/677586