删除文件的多个模式

Remove multiple patterns of a file

我有以下文件,我们称它为user.txt:

2020/06/30 22:02:58 > [+] VALID USERNAME:   admin@spookysec.local
2020/06/30 22:03:58 > [+] VALID USERNAME:   admin-svc@spookysec.local
2020/06/30 22:04:58 > [+] VALID USERNAME:   backup@spookysec.local
2020/06/30 22:05:58 > [+] VALID USERNAME:   harry@spookysec.local
2020/06/30 22:06:58 > [+] VALID USERNAME:   wrgwrsd@spookysec.local
2020/06/30 22:07:58 > [+] VALID USERNAME:   brssdb@spookysec.local
2020/06/30 22:09:58 > [+] VALID USERNAME:   a@spookysec.local
2020/06/30 22:10:58 > [+] VALID USERNAME:   adm@spookysec.local
2020/06/30 22:11:58 > [+] VALID USERNAME:   admifdfdsn@spookysec.local

我想删除每一行的多个模式,以获取每行一个用户名的用户名(例如 admin、admin-sv)。 我尝试了两个单独的 sed,效果很好,

sed -r 's/.{16}$//' user.txt > user2.txt

之后

sed -r 's/.{42}//' user2.txt > user3.txt

但我认为有一种更快、更性感的方法可以做到这一点。

尤其是这个命令

sed -r 's/(@\D+)$//' user.txt > user2.txt

不起作用。我想把@和后面的每一个字符都删掉...

有没有人知道我做错了什么以及可能的解决方案?如果我能用sed或grep达到我的目标就更好了。

你可以试试这个sed:

sed -E 's/.*[[:blank:]]|@.*//g' file

admin
admin-svc
backup
harry
wrgwrsd
brssdb
a
adm
admifdfdsn

解释:

  • .*[[:blank:]]:匹配任何0个或多个字符后跟一个空格的字符串
  • |: 或
  • @.*:匹配 @ 以及之后的所有内容

使用您展示的示例,请尝试以下代码。

第一个解决方案: 使用awk,这可以用更简单的方式完成,尝试一次。

awk -F'VALID USERNAME:[[:space:]]+|@' '{print }' Input_file

说明:这里使用awk编程。将 VALID USERNAME:[[:space:]]+|@ 作为整个 Input_file 的字段分隔符并根据要求打印每行的第二个字段。



第二个解决方案: 使用 GNU grep 请尝试以下。

grep -oP 'VALID USERNAME:[[:space:]]+\K[^@]*' Input_file

说明: 使用 GNU grep-oP 选项,其中 -o 仅打印匹配值和 -P 启用 PCRE 正则表达式。在 grep 的主程序中匹配 VALID USERNAME:[[:space:]]+ 正则表达式,然后是 \K(这将忘记以前匹配的值,以便不打印它们),然后匹配 @ 之前的所有内容以获取实际用户根据 OP 显示的样本命名。

另一个使用 sed 和捕获组的变体,在替换中使用组 1 </code>:</p> <pre><code>sed -E 's/.*[[:blank:]]([^@[:blank:]]+)@.*//' file

  • .*[[:blank:]]匹配到最后space
  • ([^@[:blank:]]+) 在组 1 中捕获匹配 @ 或 spaces
  • 以外的 1+ 个字符
  • @.* 匹配 @ 和行的其余部分

输出

admin
admin-svc
backup
harry
wrgwrsd
brssdb
a
adm
admifdfdsn

另一个使用 awk 的选项,您可以在 @

上拆分最后一列

如果split返回了2部分,可以打印第一部分:

awk '{
    nr=split($(NF), a, "@")
    if (nr==2) print a[1]
}' file

我会使用:

sed 's/.*[[:space:]]\([^[:space:]]\)//; s/@.*//'

这个和 anubhava 的(好的)答案之间的细微差别在于,如果一行末尾有杂散的白色 space,它仍然有效。

可能 unnecessary/paranoid,但视情况而定,我喜欢允许这样的情况。

如果列不同,您可以使用:

sed -E 's/(.*VALID[[:space:]]+USERNAME:[[:space:]]+)([^@[:space:]]+)(.*)//'

这匹配行中任意位置的 VALID USERNAME:,并打印下一个字段,直到但不包括第一个 @ 或 whitespace 字符。您也可以根据您的数据将模式更改为 USERNAME: 或类似模式。

最后,如果未找到 @(即电子邮件字段为空或无效),这些变体会跳过一行:

sed -n 's/.*[[:blank:]]\([^[:space:]]\)//; s/@.*//p'
sed -En 's/(.*VALID[[:space:]]+USERNAME:[[:space:]]+)([^@]+)(@.*)//p'

这可能适合您 (GNU sed):

sed -nE 's/.*\<([^@]*)@.*//p' file

捕获并打印最后一个 @ 字符之前的单词。