![sed 删除包含特定字符的确切数量的行](https://linux22.com/image/157448/sed%20%E5%88%A0%E9%99%A4%E5%8C%85%E5%90%AB%E7%89%B9%E5%AE%9A%E5%AD%97%E7%AC%A6%E7%9A%84%E7%A1%AE%E5%88%87%E6%95%B0%E9%87%8F%E7%9A%84%E8%A1%8C.png)
我想删除恰好包含的行氮一个字符的实例。在本例中,字符/
.
我更喜欢使用程序sed
。
答案1
如果必须使用sed
,则命令为:
sed -E -- '\-^([^/]*/[^/]*){3}$-d'
但如果您不需要使用sed
,最简单的解决方案是使用grep
.
将此命令中的 N 替换为您想要的值氮:
egrep -vx '([^/]*/[^/]*){N}'
grep
有一个-v
命令行选项,可以grep
显示所有执行此操作的行不是匹配正则表达式。因此,接下来的任务就是创建一个正则表达式,该表达式与恰好包含 N 次斜杠字符的行相匹配,然后grep -v
与该正则表达式一起使用。
一个例子是以下模式:
[^/]*/[^/]*
N 个实例是模式:
([^/]*/[^/]*){N}
恰好 N 个实例的模式是:
^([^/]*/[^/]*){N}$
对于仅匹配整行的模式(如本例),grep
还具有-x
命令行选项。
因此,令 N 为 3。我们的正则表达式是否可靠地仅匹配具有 3 个实例的行/
?
$ cat << EOF | egrep -x '([^/]*/[^/]*){3}'
/
//
///
////
/stuff
/stuff/added
/stuff/added/
/stuff/added/to/
/stuff/added/to/each
/stuff/added/to/each/line
more/stuff
more/stuff/added
more/stuff/added/
more/stuff/added/to/
more/stuff/added/to/each
more/stuff/added/to/each/line
consecutive//slashes/
/consecutive//slashes/
/consecutive//slashes
///all in one place
all in one place///
all in ///one place
EOF
///
/stuff/added/
more/stuff/added/
consecutive//slashes/
/consecutive//slashes
///all in one place
all in one place///
all in ///one place
是的,我们的正则表达式确实匹配了正确的行。现在我们只需将-v
标志添加到过滤掉匹配的行并显示不匹配的行。
$ cat << EOF | egrep -vx '([^/]*/[^/]*){3}'
/
//
///
////
/stuff
/stuff/added
/stuff/added/
/stuff/added/to/
/stuff/added/to/each
/stuff/added/to/each/line
more/stuff
more/stuff/added
more/stuff/added/
more/stuff/added/to/
more/stuff/added/to/each
more/stuff/added/to/each/line
consecutive//slashes/
/consecutive//slashes/
/consecutive//slashes
///all in one place
all in one place///
all in ///one place
EOF
/
//
////
/stuff
/stuff/added
/stuff/added/to/
/stuff/added/to/each
/stuff/added/to/each/line
more/stuff
more/stuff/added
more/stuff/added/to/
more/stuff/added/to/each
more/stuff/added/to/each/line
/consecutive//slashes/
答案2
您还可以使用 awk: 指定/
为字段分隔符,并查找n+1
字段。
awk -F'/' -v n=3 'NF != n + 1' file
答案3
您可以使用此 pbm。如下:
$ perl -ne 'tr|/|/| == 3 || print' inp
这里我们依靠 Perl 函数的属性tr
来返回它对输入字符串(在本例中为当前记录)所做的翻译次数。因此,当输入记录中恰好有三个斜杠时,我们不会打印该记录,但在所有其他情况下我们都会打印该记录。
这次使用的另一种方法POSIX sed
可以是:
$ sed -e 's:/:/:4;t' -e 's//\n/3' -e '/\n/d' inp
在这里,我们首先测试是否有超过 3 个斜杠,如果是,我们使用模式空间分支到 sed 代码的末尾。 OTW,模式空间中将出现 3 个或更少的斜杠。现在我们测试第三个斜杠是否可以\n
在模式空间中被换行符 , 替换。如果在这个替换之后我们看到一个换行符=>输入中正好有三个斜杠。因为我们不想看到正好 3 个斜杠,所以我们删除了这个模式空间。 OTW,剩下的任何内容(=> 具有 2 个或更少斜杠的模式空间)都会被带到标准输出。
注意:\n
在最后一种情况下无法找到,因为s//\n/3
替换不成功。
另一种使用方法POSIX sed
是:
$ sed -e h -e 's|[^/]||g' -e '/^.\{3\}$/d' -e g inp
存储当前记录的副本并删除所有非斜杠。现在检查模式空间中是否正好有三个字符(实际上现在它们都是斜杠)。如果是,我们会立即删除它。 OTW,从保留中调用存储的记录,然后 sed 默认为您打印它。
HTH。
答案4
一种方法可能是:
尝试更换(替代)(N+1)该字符第 次出现;如果替换成功,则开始新的循环(分支出)
尝试更换(替代)氮该字符第 次出现;如果替换失败,则开始新的循环(分支出)
(别的)
- 删除该行
使用 GNU sed,并采取N = 2:
$ printf 'foo/\nfoo/bar/\nfoo/bar/baz/\n' | sed -e 's,/,/,3;t' -e 's,/,/,2;T' -ed
foo/
foo/bar/baz/