删除所有与模式不匹配的行

Delete all lines which don't match a pattern

我正在寻找一种方法来删除所有不遵循特定模式的行(来自 txt 文件)。

我需要保留以下行的模式:

x//x/x/x/5/x/

x 可以是任意数量的字符、数字或特殊字符。

5 始终是字母数字的组合 - 5 个字符 - 例如 Xf1Lh,始终出现在第 5 个正斜杠之后。

/ 是实际的正斜杠。

输入:

abc//a/123/gds:/4AdFg/f3dsg34/ y35sdf//x/gd:df/j5je:/x/x/x yh//x/x/x/5Fsaf/x/ 45wuhrt//x/x/dsfhsdfs54uhb/ 5ehys//srt/fd/ab/cde/fg/x/x

期望的输出:

abc//a/123/gds:/4AdFg/f3dsg34/ yh//x/x/x/5Fsaf/x/

grep 根据正则表达式选择行,而您的 x//x/x/x/5/x/ 只需稍作改动即可使其成为正则表达式:

$ grep -E '.*//.*/.*/.*/[[:alnum:]]{5}/.*/' file
abc//a/123/gds:/4AdFg/f3dsg34/
yh//x/x/x/5Fsaf/x/

解释:

  • "x could be any amount of characters, numbers or special characters"。在 .* 的正则表达式中,. 表示任何字符,* 表示零个或多个前面的字符(在本例中为 .)。

  • “5 始终是字母数字 - 5 个字符的组合”。在 POSIX 正则表达式中,[[:alnum:]] 表示任何字母数字字符。 {5}表示前五项。 [[:alnum:]] 是 unicode 安全的。

可能的改进

一个问题是如何解释 x。在上面,x被允许是任何字符。然而,正如 triplee 指出的那样,另一个合理的解释是 x 应该是除 / 之外的任何字符。在那种情况下:

grep -E '[^/]*//[^/]*/[^/]*/[^/]*/[[:alnum:]]{5}/[^/]*/' file

此外,我们可能希望此正则表达式仅匹配 完整 行。在那种情况下,我们可以用 ^$ 包围正则表达式,或者我们可以使用 grep 的 -x 选项:

grep -xE '[^/]*//[^/]*/[^/]*/[^/]*/[[:alnum:]]{5}/[^/]*/' file

您可以使用 -P 选项来扩展 perl 支持,例如

grep -P "^(?:[^/]*/){5}[A-Za-z0-9]{5}/(?:/|$)" input

输出

abc//a/123/gds:/4AdFg/f3dsg34/
yh//x/x/x/5Fsaf/x/

正则表达式分解

^ #Start of line
 (?: #Non capturing group
    [^/]* #Match anything except /
    / #Match / literally
 ){5} #Repeat this 5 times
 [A-Za-z0-9]{5} #Match alphanumerics. You can use \w if you want to allow _ along with [A-Za-z0-9]
 (?: #Non capturing group
   / #Next character should be /
    | #OR
   $ #End of line
 )

我正在弄清楚如何在 awk 中与其他答案同时进行,并想出了:

awk -F/ 'BEGIN{OFS=FS}==""&&~/[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]/&&NF=8'

我使用的 awk 不支持 {5} regexp frob。

使用 sed 和就地编辑 删除所有不遵循特定模式的行(来自 txt 文件):

$ sed -i.bak -n "/.*\/\/.*\/.*\/.*\/[a-zA-Z0-9]\{5\}\/.*\//p" test.in
$ cat test.in
abc//a/123/gds:/4AdFg/f3dsg34/
yh//x/x/x/5Fsaf/x/

-i.bak 就地编辑创建一个 test.in.bak 备份文件,-n 安静,不打印不匹配的输出 和 ".../p" 打印匹配项。