Awk (или sed/grep), чтобы получить вхождения подстроки

У меня есть строка json в переменной bash, которая выглядит примерно так:

{
    "items": [
      {
        "foo": null,
        "timestamp": 1553703000,
        "bar": 123
      },
      {
        "foo": null,
        "timestamp": 1553703200,
        "bar": 456
      },
      {
        "foo": null,
        "timestamp": 1553703400,
        "bar": 789
      }
    ]
}

Я хочу знать, сколько из этих timestamps после заданной даты и времени, поэтому, если у меня есть 1553703100, он вернется 2.

(Бонусные воображаемые баллы, если вы можете дать мне именно это число!)

В качестве шага к этому я хочу получить только совпадения "timestamp": \d+, в строке, чтобы я мог перебирать их в сценарии bash.

Я немного использовал sed и grep, но никогда не использовал awk, и, судя по моему чтению, это может лучше соответствовать задаче.

Другая информация: - JSON уже напечатан красиво, как указано выше, поэтому временные метки всегда будут на отдельных строках. - Это для запуска в Cygwin, поэтому у меня есть awk/gawk, sed и grep/egrep, но, вероятно, не другие. - Может быть любое количество временных меток в json.

Используйте 'jq' для разбора JSON

Gilles Quenot 10.04.2019 23:38

@GillesQuenot, OP указал доступные инструменты

vintnes 10.04.2019 23:43
jq доступен на cygwin.
Ed Morton 10.04.2019 23:43

Я не знаю, как использовать jq, потому что все так заняты тем, что говорят мне использовать его, что забывают публиковать с ним реальные решения.

vintnes 10.04.2019 23:46

Всем спасибо! Оба ответа превосходны. Оказывается, у меня не установлено jq, поэтому я буду использовать решение awk. Хотел бы я отметить 2 ответа как принятые :-(

Redzarf 11.04.2019 00:01

Привет @Redzarf, спасибо за согласие. Пожалуйста, смотрите мое обновление для важных изменений, необходимых для производственного кода.

vintnes 11.04.2019 00:58

Я также добавил решение для Python ;-) Надеюсь, это поможет

Allan 11.04.2019 02:22
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
176
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

редактировать: Второй подход, указанный ниже, имеет серьезные проблемы, которые были очень любезно описаны @EdMorton. Я решил оставить старый код в образовательных целях.

Избежал substr() и поймал нулевую строку i:

$ awk -v dt=1553703100 '
  /timestamp/ && $2+0>dt {i++}
  END {print i+0}
' <<< "$var"

2

ВНИМАНИЕ: ПРОБЛЕМАТИЧЕСКИЙ КОД

Здесь я использовал substr(string, index, [characters]), чтобы обрезать запятую во втором поле. Регулярное выражение /timestamp/ не сложное; его можно было бы улучшить, если бы ваш json стал более сложным.

$ awk -v dt=1553703100 '
  /timestamp/ && substr($2, 0, length($2)) > dt {i++} 
  END {print i}
' <<< "$var"

2

Второй аргумент для substr() — это начальная позиция подстроки. Все индексы массива, поля и строки в awk начинаются с 1, а не с 0. Когда вы используете 0 в качестве второго аргумента для substr(), awk обрабатывает его так же, как любое другое недопустимое значение (попробуйте awk 'BEGIN{print substr("bananas",-27,3)}'), и обрабатывает его так, как если бы вы указан 1 вместо этого. Третий аргумент - это длина подстроки. Использование length($2) — это то же самое, что оставить это поле пустым, поскольку оно даст вам полную длину строки. ITYM substr($2, 1, length($2)-1), но вместо этого вы можете просто использовать $2+0, чтобы раздеть ,.

Ed Morton 11.04.2019 00:07

Окончательный вывод должен быть print i+0, чтобы вы получали числовой вывод, даже если никакие значения не совпадают (в отличие от вывода нулевой строки в этом случае).

Ed Morton 11.04.2019 00:09

Вы не предоставили ожидаемый результат, так что это предположение, но это то, что вы пытаетесь сделать?

$ echo "$var" | jq '.items[].timestamp'
1553703000
1553703200
1553703400

или, может быть:

$ echo "$var" | jq '.items[].timestamp | select(. > 1553703100)'
1553703200
1553703400

или:

$ echo "$var" | jq '[.items[].timestamp | select(. > 1553703100)] | length'
2

ВНИМАНИЕ: я только учусь jq, так что могут быть лучшие способы сделать вышеперечисленное!

Аккуратно, спасибо. OP указал, что он хочет, чтобы количество записей превышало указанную отметку времени. Есть ли способ сделать это в jq?

vintnes 10.04.2019 23:51

@vintnes Я погуглил несколько jq примеров и обновил свой ответ на их основе.

Ed Morton 10.04.2019 23:58

Вы также можете быстро реализовать python решение:

Вход:

$ cat data.json 
{
    "items": [
      {
        "foo": null,
        "timestamp": 1553703000,
        "bar": 123
      },
      {
        "foo": null,
        "timestamp": 1553703200,
        "bar": 456
      },
      {
        "foo": null,
        "timestamp": 1553703400,
        "bar": 789
      }
    ]
}

код:

$ cat extract_value2.py 
import json

tLimit = 1553703100
with open('data.json') as f:
    data = json.load(f)
    print([t['timestamp'] for t in data["items"] if t['timestamp'] > tLimit])

выход:

$ python extract_value2.py 
[1553703200, 1553703400]

код счета:

$ cat extract_value2.py 
import json

tLimit = 1553703100
with open('data.json') as f:
    data = json.load(f)
    print(len([t['timestamp'] for t in data["items"] if t['timestamp'] > tLimit]))

выход:

$ python extract_value2.py
2 

Другие вопросы по теме