替换第二次出现的行

替换第二次出现的行

我想yyyy-mm-dd hh:mm:ss从下面的文件中删除除第一个之外的所有出现的内容。所以基本上我希望显示该行的第一次出现,并且我希望删除所有剩余的重复行。有人可以帮助我使用正则表达式 cmd 来做到这一点吗?

Will use per-minute statistics
Stats from 2016-06-26   00:00:00 to 2016-06-26  23:59:00
yyyy-mm-dd      hh:mm:ss
6/26/2016       0:01:00
6/26/2016       0:03:00
yyyy-mm-dd      hh:mm:ss
6/26/2016       0:01:00
yyyy-mm-dd      hh:mm:ss
6/26/2016       0:01:00
6/26/2016       0:02:00
6/26/2016       0:03:00

答案1

如果您只想删除所有重复的 yyyy-mm-dd 行,那么

% sed '/^yyyy-mm-dd/,$ { n ; /^yyyy-mm-dd/d }' srcfile
Will use per-minute statistics
Stats from 2016-06-26   00:00:00 to 2016-06-26  23:59:00
yyyy-mm-dd      hh:mm:ss
6/26/2016       0:01:00
6/26/2016       0:03:00
6/26/2016       0:01:00
6/26/2016       0:01:00
6/26/2016       0:02:00
6/26/2016       0:03:00

如果你想删除所有重复的行,那么这有点hack'n'slashy并且效率低下,但是有效并且很容易理解。 (您可以优化第二个 sed | grep,但这样更容易阅读,恕我直言)。

% sed -n '1,/^yyyy-mm-dd/p' srcfile ; sed '1,/^yyyy-mm-dd/d' srcfile | grep -v ^yyyy-mm-dd | sort -u
Will use per-minute statistics
Stats from 2016-06-26   00:00:00 to 2016-06-26  23:59:00
yyyy-mm-dd      hh:mm:ss
6/26/2016       0:01:00
6/26/2016       0:02:00
6/26/2016       0:03:00

答案2

正确的工具是 awk。它可以让您以简单的方式表达逻辑:seen第一次看到模式时设置一个变量,如果已经看到模式,则跳过与模式匹配的行。如果没有跳过一行,则打印它。

awk '/^yyyy-mm-dd[ \t]+hh:mm:ss$/ {if (seen) next; ++seen}
     1 {print}'

这可以缩写,但会变得更加神秘。

awk '!(/^yyyy-mm-dd[ \t]+hh:mm:ss$/ && !(seen++))'

答案3

sed -e '0,/^yyyy-mm-dd\s\+hh:mm:ss$/!{/^yyyy-mm-dd\s\+hh:mm:ss$/d}'

(GNU sed 功能)范围0,/pattern/匹配到第一次出现,因此在文件的其余部分0,/pattern/!运行 的内容,删除所有后面的匹配项。{...}

答案4

GNU支持正则表达式地址的数字偏移,因此您可以寻址从到文件末尾的ed范围。然后,您可以删除与该范围内的相同正则表达式匹配的任何行。最后写入修改后的文件并退出。 /pattern/+1$g//d

ed file << EOF
/^yyyy-mm-dd/+1,$ g//d
wq
EOF

或同等地

 printf '/^yyyy-mm-dd/+1,$ g//d\nwq\n' | ed file

相关内容