如何grep在特定列中具有特定值的行?


9

我有一个如下文件

  200.000    1.353    0.086
  200.250    1.417    0.000
  200.500    1.359    0.091
  200.750    1.423    0.000
  201.000    1.365    0.093
  201.250    1.427    0.000
  201.500    1.373    0.093
  201.750    1.432    0.000
  202.000    1.383    0.091
  202.250    1.435    0.000
  202.500    1.392    0.087
  202.750    1.436    0.000
  203.000    1.402    0.081
  203.250    1.437    0.001
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045  

我只想grep第一列中只有十进制.000和.500的行,所以输出将是这样的

  200.000    1.353    0.086
  200.500    1.359    0.091
  201.000    1.365    0.093
  201.500    1.373    0.093
  202.000    1.383    0.091
  202.500    1.392    0.087
  203.000    1.402    0.081
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045  

2
看起来很容易。你都尝试了些什么?您的代码有什么问题?
John1024 '16

也许对您来说很容易,但是我尝试使用grep'.000'| grep'.005',但也会对其他列中具有相同值的行进行排序
Mohsen El-Tahawy

3
很好。如果您表现出诚实的尝试自己解决问题,那么这里的人们会更加同情。注释中的代码显示了这一点。将来,如果您在问题中包含类似的尝试,则可能会更快地获得更好的响应。
John1024 '16

Answers:


14

您不使用grep。使用awk

"your data" | awk '$1 ~ /\.[05]00/'

很好。按照编写的方式,代码取决于小数点后是否恰好有三位数。使用起来会更健壮awk '$1 ~ /\.[05]0*$/'
John1024 '16

1
@ John1024,实际上写成的代码取决于小数点后至少有三位数。我会倾向于awk '$1 ~ /\.[05]00$/',我本人(精确地要求三位数字),除非我有理由认为输入中应该包含可变的小数位。
2016年

2
@Wildcard如果超过三个,则代码可能会失败。例如:echo 0.5001 | awk '$1 ~ /\.[05]00/'。它只有在有工作可靠准确三人。
John1024 '16

4
awk '$1 ~ /\.[50]00/ { print $0 }' myFile.txt

第一列$1将与/\.500|\.000/点匹配,将点转义为文字点而不是正则表达式的任何字符~(部分匹配),并打印整行$0


2
没有理由包括{ print $0 }; 这是Awk的默认操作。
2016年

4

我只想grep第一列中具有十进制.000和.500的行

我的第一个念头

grep '^ *[0-9][0-9][0-9]\.[50]00' filename

使用WSL进行快速测试

$ head testdata
              200.000    1.353    0.086
              200.250    1.417    0.000
              200.500    1.359    0.091
              200.750    1.423    0.000
              201.000    1.365    0.093
              201.250    1.427    0.000
              201.500    1.373    0.093
              201.750    1.432    0.000
              202.000    1.383    0.091
              202.250    1.435    0.000
$ grep '^ *[0-9][0-9][0-9]\.[50]00' testdata
              200.000    1.353    0.086
              200.500    1.359    0.091
              201.000    1.365    0.093
              201.500    1.373    0.093
              202.000    1.383    0.091
              202.500    1.392    0.087
              203.000    1.402    0.081
              203.500    1.412    0.073
              204.000    1.423    0.065
              204.500    1.432    0.055
              205.000    1.441    0.045

有更多简洁的方法可以表达这一点。

$ grep -E '^ *[0-9]{3}\.[50]00' testdata
              200.000    1.353    0.086
              200.500    1.359    0.091
              201.000    1.365    0.093
              201.500    1.373    0.093
              202.000    1.383    0.091
              202.500    1.392    0.087
              203.000    1.402    0.081
              203.500    1.412    0.073
              204.000    1.423    0.065
              204.500    1.432    0.055
              205.000    1.441    0.045

如果第一列可能不是三位数整数部分

grep -E '^ *[0-9]+\.[05]00' testdata

在某些情况下,您可能需要使用[:digit:]代替[0-9]

等等。

man grep 是你的朋友。


的这种用法grep比我的易于使用。如果我先看到这个,我不会发布答案。不错的工作!
Yokai's

2

根据您的用例,您可能还会使用实际的数字运算:

$ awk '{a = $1 % 1} a == 0 || a == 0.5' /tmp/foo
  200.000    1.353    0.086
  200.500    1.359    0.091
  201.000    1.365    0.093
  201.500    1.373    0.093
  202.000    1.383    0.091
  202.500    1.392    0.087
  203.000    1.402    0.081
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045

使用BSD awk(OSX El Capitan,20070501)和GNU awk 4.1.4进行了测试。


1
警告:测试浮点数(awk使用的)的精确相等性通常会得出“错误”的结果,除非这些值没有小数部分(并且幅度不大),或者小数部分是“二进制”(恰好是一半,四分之一等)对于此Q中的数据是正确的,但看起来与未初始化数据相似的其他变量并不多。
dave_thompson_085 '16

1
@ dave_thompson_085确实是,但是使用gawk可以使用任意精度算术,但我在这里没有使用它们。
muru


2

awk

$>awk '$1%.5==0' data.tsv 
200.000 1.353   0.086
200.500 1.359   0.091
201.000 1.365   0.093
201.500 1.373   0.093
202.000 1.383   0.091
202.500 1.392   0.087
203.000 1.402   0.081
203.500 1.412   0.073
204.000 1.423   0.065
204.500 1.432   0.055
205.000 1.441   0.045

mlr

$>mlr --ifs tab --onidx filter '$1%.5==0' data.tsv 
200.000 1.353 0.086
200.500 1.359 0.091
201.000 1.365 0.093
201.500 1.373 0.093
202.000 1.383 0.091
202.500 1.392 0.087
203.000 1.402 0.081
203.500 1.412 0.073
204.000 1.423 0.065
204.500 1.432 0.055
205.000 1.441 0.045

2

好的,我的贡献有点晚了,但是我认为这是值得的。

根据OP,要满足的要求是第一列的十进制值为.000.500。没有关于范围或长度的领先值的规定。对于稳健它不应该被假定为被任何东西所限制,除了有第一栏前没有非空白字符(或它不再是第一列),且第一列的内容有一个小数点,.,在某处。

OP希望使用grep,当找到匹配项时,它将打印整行,因此,唯一要做的就是创建匹配所有内容匹配所需内容的模式。

本身很简单,没有理由使用grep sedawk将其作为文件或管道来处理源代码。

grep文件使用grep '^[^.]*\.[05]0\{2\}\s' the_file.txt

要从grep管道使用my_command | grep '^[^.]*\.[05]0\{2\}\s'

模式是:^,从行的开头开始;[^.],匹配任何非十进制字符;*,尽可能多次(包括无);\.,匹配小数点;[05],匹配五或零;0\{2\},再匹配2个零(开括号和闭括号之前的反斜杠可防止外壳尝试进行括号扩展);\s,请匹配空白字符(表示列的末尾-以在不同的用例中使用,请替换为列分隔符,通常是逗号,分号或制表符\t)。

请注意,这将完全符合OP的要求。它将匹配.5000或者.0000即使数字等同,因为该模式寻找一个五零,后紧跟2多个零后面的空格。如果那很重要,那么到目前为止,所有其他答案都将失败,因为它们将匹配测试数字后的任意多个零,大于1。而除了通过FloHimself答案,他们会匹配任何在第二个栏开始 .000.500,包括.0003.500T,和一个由FloHimself将匹配任何在数学上等价于.0.5,无论有多少个零。最后一个虽然不符合OP的规定,但很可能仍符合OP的需求。

最后,awk即使OP要求,如果仍需要功率和速度grep,则命令将是:

带文件 awk '$1 ~ /[^.]\.[05]0{2}$/' the_file.txt

带管 my_command | awk '$1 ~ /[^.]\.[05]0{2}$/'


1

如果您坚持使用grep,那么这可能对您有用。我将您提供的第一个输出保存到名为“ file.txt”的文本文件中,然后使用以下命令:

grep -e '2[^ ]*.000' file.txt & grep -e '2[^ ]*.500' file.txt

输出为:

200.000    1.353    0.086
200.500    1.359    0.091
201.500    1.373    0.093
201.000    1.365    0.093
202.500    1.392    0.087
202.000    1.383    0.091
203.500    1.412    0.073
203.000    1.402    0.081
204.500    1.432    0.055
204.000    1.423    0.065
205.000    1.441    0.045

如果输出已经存在于文件中,则无需将其保存到文本文件中。但是,如果未将其保存到文件中,则还可以将数据通过管道传递到我提供的grep命令中,并且至少应2在第一列中的第一个数字a之前起作用2。此时,您将需要使用适当的字符更新grep命令以正确打印。

此双重grep命令正在发生的事情是,第一个命令grep正在与&操作员一起发送到后台。当它发送到后台时,下grep一条命令将立即执行,并为您提供统一的输出。为了使您更轻松地完成需要完成的任务,您应该遵循别人给出的示例,awk甚至使用sed

(编辑)

这绝不是满足您需求的grep的最佳或最有效的用法,但它足以让您稍微适应一下并获得更好的grep感觉。


第一个进程确实在后台运行,但是没有守护进程,其中包括在后台运行,但还有很多。而且产生与输入顺序相同的输出的可能性很小。即使在非常小的示例中,它在第三行也已经出错。
dave_thompson_085 '16

他没有提到输出需要按特定顺序排列。只是它需要特定于第一列的.500.000。如果需要按照特定的顺序(例如从最小到最大)进行操作,则很容易做到。但是,要打印的第一列的前3位至少是最大顺序。那是2[^ ]*.000and 的结果2[^ ]*.500。这完全符合OP的要求。
Yokai's

还要注意我对所提供命令的效率免责声明的编辑。
Yokai's
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.