Grep删除0而不是0.2的行?


12

我有一个文件,其内容与以下文件相似。

0
0
0.2
0
0
0
0

我需要删除所有带有单个零的行。
我正在考虑使用grep -v "0",但这也会删除包含0.2的行。我看到我可以使用该-w选项,但这似乎也不起作用。

如何删除仅包含一个0的所有行,并保留所有以0开头的行?



1
@JulienLopez不是那个问题的虚伪。该问题是关于匹配单词,并用回答-w,此处失败。
Sparhawk

您为什么被迫使用grep此任务?那么,一个零到底是什么意思呢?这听起来很像XY问题
罗兰·伊利格

1
@RolandIllig,就在睡前1个小时,我想开始处理一系列500,000个字符串,以检查它们是否是比特币私钥,如果可以的话,请保持平衡。下次我有时间查看它时,我已经处理了成千上万个字符串,而我只想解析任何非零值。
菲利普·柯比布里德

Answers:


35
grep -vx 0

来自man grep

-x, --line-regexp
       Select only those matches that exactly match the whole line.
       For a regular expression pattern, this is like parenthesizing
       the pattern and then surrounding it with ^ and $.

-w失败,因为先00.02被认为是“单词”,因此该行是匹配的。这是因为其后跟一个“非单词”字符。如果运行不带的原始命令-v,即可以看到此内容grep -w "0"


您还可以使用该-F选项,因为我们不使用正则表达式模式,仅使用纯字符串匹配
glenn jackman

@glennjackman也许我以前读过,但是现在似乎找不到。与-F我一起跑步(令我惊讶的是)似乎花费了类似的时间,甚至稍微慢一点(〜5–10%)。因此,我不确定会有什么好处。
Sparhawk

2
RegEx引擎的使用频率如此之高和广泛使用,以至于他们实施了非常高效的版本,但“普通搜索”可能已经30年没有升级了。
尼尔森

@Sparhawk:grep对于没有元字符的正则表达式,大概有一个特殊情况,因为这是一个常见的用例。令人惊讶的是它的fgrep速度会变慢,但是与扫描大文件的时间相比,在编译短模式时注意到这种特殊情况的开销可以忽略不计,这并不奇怪。(如果需要某种特殊情况来加快速度,那么相对于具有字符类或x.*y。的模式)
Peter Cordes,

但这可能是一个过分的简化,因为输入实际上是许多短行(不是一个大字符串)。我忘记了是否grep\n换行符以外的其他字符识别为行分隔符。如果不是,则隐式^$ 仍然可以变成固定字符串搜索,例如strstr(big_buf, "\n0\n")。(或者0\n在缓冲区的开头。)但是,我们不只是寻找可能进入较大缓冲区的第一个匹配项,还希望有效过滤。但是无论如何,从理论上讲,是的,每行的开头只是一个2字节的memcmp,您希望fgrep和grep都能看到这一点。
彼得·科德斯


14

尽管grep 可以用于此目的(其他答案清楚地表明),但让我们退后一步,思考一下您真正想要的是什么:

  • 您有一个包含数字的文件
  • 您要基于数值执行过滤。

正则表达式解释字符序列数据。他们不知道数字,只知道单个数字(及其常规组合)。尽管在您的特定情况下,围绕此限制有一个简单的解决方法,但最终是需求不匹配。

除非有很好的理由在grep这里使用(例如,因为您已经对其进行了测量,并且效率大大提高,并且效率对您而言至关重要),否则我建议您使用其他工具。

awk,例如,可以基于数值比较进行过滤,例如:

awk '$1 == 0' your_file

而且,要获得所有包含大于零的数字的行:

awk '$1 > 0' your_file

我喜欢regex,这是个很棒的工具。但这不是唯一的工具。俗话说,如果只有grep,一切看起来就像是普通语言。


3
我全心全意地同意awk在这里可能会更优雅...但是,它也可能比用户期望的匹配得多(每个数值评估为0)。即,printf '0\n1\n-1\na\nb\n0\n0 also\n0.0\n-0.0\n0*0\n' | awk '($1 == 0)'将匹配:00.0-0.0...也0 also!不只是“ 0”。(有时需要,有时则不需要)。如果用户只需要“ 0” :(awk '/^0$/'grep '^0$')。您还应该编辑:用户需要添加!否定测试,以便隐藏0(和其他零)并显示其余部分。即:awk '!( $0 == 0)'
奥利维尔·杜拉克

1
@Olivier,或检查字符串值:$1 == "0"
glenn jackman

1
@OlivierDulac我显式使用>而不是!=(或等效地! (… == …))来强调这是一个任意的数值比较,而不仅仅是相等。至于您的其他评论,这是完全正确的,但随后我们基本上回到了字符串比较领域和使用grep工作的现有解决方案(尽管awk当然也可以工作)。
康拉德·鲁道夫

@KonradRudolph积分:)
奥利维尔·杜拉克

1
@glennjackman:确实不错。但随后OP宁愿进行测试$0=="0"
Olivier Dulac

5

grep-w有点在于它拆分了原来的串入字和非词的成分(任何东西,除了字母,数字或下划线)的方式令人费解。由于它已经遇到一个有效的单词成分00.02因此它声明了否定逻辑以删除该行。

sed在这种情况下,使用起来很容易,只需删除匹配的整个单词

sed '/^0$/d' file

3

当您要删除的行仅包含一个0 后跟下一行时,您可以通过发出以下命令来选择这些行:

grep -v "^0$"

这将只打印的出现0在一行的末尾,并在一行的开头在同一时间。-v然后,该选项会反转我们的选择。


1
这个答案与Arkadiusz Drabczyk的答案几乎相同,但是您忘记了-v,所以它不起作用。
Sparhawk

你是对的。当他发布答案时,我正在打字,所以我没有看到答案。我对该-v选项有误读,谢谢!
majesticLSD

0
  • \ b-单词边框

grep -v "\b0\b"

  • 匹配行首,您的模式和行尾

grep -v "^0$"

  • 或如@Sparhawk建议的-vx lineregexp

-w有效,但是在您的情况下0.2是两个单词,因为点字符是一个单词分隔符。


grep -v "\b0\b"在这里真的不工作。您使用什么版本的grep?
Arkadiusz Drabczyk '19

有工作grep (BSD grep) 2.5.1-FreeBSD在Mac OS和grep (GNU grep) 2.16Ubuntu上
的Jakub Jindra

1
GNU正则表达式使用\<\>作为单词边界,但效果与-w
glenn jackman

0

假设您启用了PCRE,那么为了多样化,另一个答案是 grep

grep -Pv "^0(?!\.)"

这将执行否定的前瞻,以匹配以开头0且后面没有点的线。然后-v丢弃不匹配的行。您可以在这里看到实际效果


1
这也将删除行,例如0123,这不是OP想要的
-iruvar

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.