Как получить строки, которые имеют определенное значение в определенном столбце?

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
может быть, это легко для вас, но я попробовал с grep '.000' | grep '.005', но также сортирует строки с одинаковым значением в других столбцах
Мохсен Эль-Тахави,
3
Отлично. Люди здесь гораздо более сочувствующие, если вы демонстрируете честную попытку решить проблему самостоятельно. Код в вашем комментарии показывает это. В будущем, если вы включите подобные попытки в свой вопрос, вы, скорее всего, получите лучшие ответы быстрее.
John1024

Ответы:

14

Вы не используете grep. Использование awk.

"your data" | awk '$1 ~ /\.[05]00/'
azzid
источник
Отлично. Как написано, код зависит от того, чтобы после десятичной точки было ровно три цифры. Было бы более надежным в использовании awk '$1 ~ /\.[05]0*$/'.
John1024
1
@ John1024, на самом деле, как написано, код зависит от того, чтобы после десятичной точки было как минимум три цифры. Я бы склонялся к awk '$1 ~ /\.[05]00$/'себе (потребовал ровно три цифры), если только у меня не было оснований полагать, что на входе ожидаются переменные десятичные разряды.
Подстановочный
2
@Wildcard Если их больше трех, код может не работать. Например: echo 0.5001 | awk '$1 ~ /\.[05]00/'. Надежно работает только если их ровно три.
John1024
4
awk '$1 ~ /\.[50]00/ { print $0 }' myFile.txt

Первый столбец $1будет сопоставлен с /\.500|\.000/точками, которые экранируются, чтобы быть буквальными точками, не выявлять символы, ~совпадающие с частичными, и выводить всю строку$0

Dalvenjia
источник
2
Нет причин для включения { print $0 }; это действие Awk по умолчанию.
Подстановочный
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

Если первый столбец может содержать целую часть, отличную от 3 цифр

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

При некоторых обстоятельствах вам может потребоваться использовать [:digit:]вместо [0-9].

И так далее.

man grep твой друг.

RedGrittyBrick
источник
Это использование grepпроще в использовании, чем у меня. Я бы не отправил ответ, если бы увидел это первым. Хорошая работа!
Йокай
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) часто дает «неправильные» результаты, если только значения не имеют дробной части (и не слишком велики по величине), или дробная часть является «двоичной» (ровно половина, четверть и т. д.), что верно для данных в этом вопросе, но не для многих других, которые выглядят как непосвященные.
dave_thompson_085
1
@ dave_thompson_085 действительно, но с gawk вы можете использовать арифметику произвольной точности , правда, я здесь их не использую.
Муру
2
 grep -e '2[^ ]*.000' -e '2[^ ]*.500' file.txt
принц 987
источник
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
FloHimself
источник
2

Хорошо, немного опоздал с добавлением моего вклада, но я думаю, что оно того стоит.

Требование к выполнению согласно ОП - это первый столбец с десятичным значением .000или .500только. Там нет никаких оговорок в отношении ведущего значения, ни по диапазону, ни по длине. Для надежности не следует предполагать, что он ограничен ничем, кроме того, что перед первым столбцом нет непустых символов (или это уже не первый столбец) и что содержимое первого столбца будет иметь десятичную точку ., в этом где-то.

OP хочет использовать grep, который будет печатать всю строку, когда найдено совпадение, поэтому единственное, что нужно сделать, это создать шаблон, который соответствует всем и только тому, что требуется.

Сама простота и отсутствие причин использовать sedили awkкак `grep может обрабатывать исходный код как файл или канал.

Для grepиспользования файлаgrep '^[^.]*\.[05]0\{2\}\s' the_file.txt

Чтобы grepиз трубы использоватьmy_command | grep '^[^.]*\.[05]0\{2\}\s'

Шаблон:, ^начать с начала строки; [^.]соответствовать любому не десятичному символу; *столько раз, сколько возможно (включая ни одного); \.соответствует десятичной запятой; [05]соответствует либо пять, либо ноль; 0\{2\}, сопоставьте еще 2 нуля (обратная косая черта перед открывающей и закрывающей скобкой не позволяет оболочке попытаться выполнить расширение скобки); \s, соответствует символу пробела (имеется в виду конец столбца - для использования в другом случае, замените его разделителем столбца, обычно это запятая, точка с запятой или табуляция \t).

Обратите внимание, что это будет точно соответствовать тому, что спросил ОП. Он не будет совпадать .5000или .0000даже численно эквивалентен, потому что шаблон ищет пять или ноль, за которыми следуют ровно 2 ноля, за которыми следует пробел. Если это важно, то все остальные ответы до сих пор терпят неудачу, так как они будут соответствовать любому количеству нулей, больше 1, после контрольной цифры. И кроме ответа от FloHimself, они будут соответствовать чему-либо во втором столбце, который начинается .000 или .500, включая .0003и .500T, и тот, что FloHimself, будет соответствовать всему, что математически эквивалентно .0и.5независимо от того, сколько нулей. Последний, хотя и не соответствует заявленному ФП, в любом случае, скорее всего, будет соответствовать его нуждам.

Наконец, если awkтребуется мощность и скорость, даже если запрашивается OP grep, тогда команда будет:

С файлом awk '$1 ~ /[^.]\.[05]0{2}$/' the_file.txt

С трубкой my_command | awk '$1 ~ /[^.]\.[05]0{2}$/'

user207673
источник
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, в первом столбце больше нет 2. В этот момент вам нужно обновить команду grep соответствующим символом для правильной печати.

Что происходит с этой двойной grepкомандой, так это то, что первая grepотправляется на задний план с &оператором. Поскольку она отправляется в фоновый режим, следующая grepкоманда выполняется сразу же после этого, давая вам одинаковый вывод. Чтобы задача, которую вам нужно было выполнить, была более легкой, вы должны следовать примеру, который другие приводили, использовали awkили даже использовали sed.

(редактировать)

Это ни в коем случае не лучшее и не самое эффективное использование grep для ваших нужд, но этого должно быть достаточно, чтобы вы немного поиграли и лучше почувствовали grep.

Yokai
источник
Первый процесс выполняется в фоновом режиме, но не демонизирован, что включает запуск в фоновом режиме, но немного больше. И это очень маловероятно, чтобы производить выходные данные в том же порядке, что и входные данные; даже в вашем довольно маленьком примере это уже пошло не так в третьей строке.
dave_thompson_085
Он не упоминает, что вывод должен быть в определенном порядке. Только то , что нужно конкретно к .500и .000первому столбцу. Если это необходимо в определенном порядке, например, от наименьшего к наибольшему, это легко сделать. Однако первые 3 цифры первых печатаемых столбцов располагаются в наименьшем порядке. Это результат 2[^ ]*.000и 2[^ ]*.500. Это вполне соответствует тому, что спросил ОП.
Йокай
Также обратите внимание на мою правку об отказе от ответственности за предоставленную мною команду.
Йокай