在 bash 中从文件中删除以 开头且不以 结尾的行

在 bash 中从文件中删除以 开头且不以 结尾的行

我读过很多关于如何删除以特定字符或字符集开头的行的 sed 示例,这并不具有挑战性,但我似乎无法破解这个示例。我想删除文件中以字母“i”开头且不以“.conf”结尾的所有行。

以下是列表示例:

include /usr/local/choops/users/2488.conf
include /usr/local/cho
include /usr/local/choops/users/2492.conf
i
incl

上例中需要删除的 3 行是:

include /usr/local/cho
i
incl

它们是不完整的,不能在那里。

我尝试了在 StackExchange 和 StackOverflow 以及其他各种论坛上看到的示例的一些变体,但我似乎无法做到正确。这是我尝试过的:

sed -i '/^i.*[^\.conf]$/d' /usr/local/choops/users/main.conf

sed -i '/^i.\*\[^\\.conf\]$/d' /usr/local/choops/users/main.conf

sed -i '/^i.*[^.conf]$/d' /usr/local/choops/users/main.conf

其中 main.conf 是列出一组 .conf 文件的文件,如上所示。我认为这个不会太复杂,但这些命令似乎都不适合我。我根据各种来源和对 sed 的理解构建了命令。任何帮助将不胜感激,我很困惑。

以下内容与我想要的相反,但我想这很简单:

sed -i 's/i.*.conf//' main.conf

答案1

有两个子句必须同时满足(“以 i 开头”、“不以 .conf 结尾”)。对于要从​​输出中排除的行,需要单独测试每个子句,然后将其与在一起。

输入示例(添加了不以“i”开头的额外行):

$ cat input.txt 
include /usr/local/choops/users/2488.conf
this line doesn't begin with i
include /usr/local/cho
this line doesn't begin with i but does end in .conf
include /usr/local/choops/users/2492.conf
i
incl

perl

$ perl -ne 'print unless (/^i/ && ! /\.conf$/)' input.txt 
include /usr/local/choops/users/2488.conf
this line doesn't begin with i
this line doesn't begin with i but does end in .conf
include /usr/local/choops/users/2492.conf

sed

$ sed -ne '/^i/ {/\.conf$/!d;};p' input.txt 
include /usr/local/choops/users/2488.conf
this line doesn't begin with i
this line doesn't begin with i but does end in .conf
include /usr/local/choops/users/2492.conf

或者(可能更好),正如 @seshoumara 建议的那样:

sed -e '/^i/ {/\.conf$/!d;}' input.txt

所有三个版本都从输出中删除不需要的行,打印其他所有内容。

答案2

看来你有两个条件,如果行以“i”开头,如果行不以“.conf”结尾,则为 true。不要进行一次搜索,而是分两次进行。

sed -i '/^i/{/\.conf$/!d}' /usr/local/choops/users/main.conf

或者,如果你有相反的事情,就否定它。

sed -i '/^i.*\.conf$/!d' /usr/local/choops/users/main.conf

请注意,点需要转义,否则它是一个表示任何字符的正则表达式。

您尝试的“[^abc]”正则表达式实际上表示:不是“a”、“b”或“c”的单个字符。可能是“j”或“z”。无论该正则表达式匹配什么,它仍然是单个字符。最后,“[]”或“[^]”中的字符不能具有任何正则表达式含义,而只是文字字符列表,因此“.”总是意味着点,不需要转义它。但在 // 或 s/// 中,您希望根据您的情况将其转义。

答案3

我想删除文件中以字母“i”开头且不以“.conf”结尾的所有行

  • 让我们A表示“以字母开头i
  • 让我们B表示“结束于.conf

使用布尔逻辑我们可以说你想要删除匹配条件“A and not B”的行:

A . B'

此外,我们可以将其重写为“{ not A, or B } 的否定”:

( A' + B'' )' = ( A' + B )'

使用grep我们可以将其反转为保持(而不是删除)与表达式匹配的行,因此:

( A' + B )

在代码中这将变成,

grep -E '^[^i]|\.conf$'

尽管实际上我们还需要考虑根本不以任何字符开头的行(即它们是空白的),

grep -E '^[^i]|\.conf$|^$'

使用示例文件,您可以保留这些行:

include /usr/local/choops/users/2488.conf
include /usr/local/choops/users/2492.conf

通常的规则适用于就地编辑(这是烟雾和镜子),所以我们自己应用它

grep ... file >file.tmp &&
    mv -f -- file.tmp file
rm -f -- file.tmp

答案4

begin with the letter "i" and DO NOT end with ".conf"使用任何 awk,我们只需将您指定的匹配要求转换为代码即可识别您要删除的行:

$ awk '/^i/ && !/\.conf$/' file
include /usr/local/cho
i
incl

然后简单地否定该条件以获得您想要保留的行:

$ awk '!(/^i/ && !/\.conf$/)' file
include /usr/local/choops/users/2488.conf
include /usr/local/choops/users/2492.conf

如果您愿意,可以缩写为德摩根定律到:

$ awk '!/^i/ || /\.conf$/' file
include /usr/local/choops/users/2488.conf
include /usr/local/choops/users/2492.conf

相关内容