У меня есть строка 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.
@GillesQuenot, OP указал доступные инструменты
jq доступен на cygwin.
Я не знаю, как использовать jq, потому что все так заняты тем, что говорят мне использовать его, что забывают публиковать с ним реальные решения.
Всем спасибо! Оба ответа превосходны. Оказывается, у меня не установлено jq, поэтому я буду использовать решение awk. Хотел бы я отметить 2 ответа как принятые :-(
Привет @Redzarf, спасибо за согласие. Пожалуйста, смотрите мое обновление для важных изменений, необходимых для производственного кода.
Я также добавил решение для Python ;-) Надеюсь, это поможет





редактировать: Второй подход, указанный ниже, имеет серьезные проблемы, которые были очень любезно описаны @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, чтобы раздеть ,.
Окончательный вывод должен быть print i+0, чтобы вы получали числовой вывод, даже если никакие значения не совпадают (в отличие от вывода нулевой строки в этом случае).
Вы не предоставили ожидаемый результат, так что это предположение, но это то, что вы пытаетесь сделать?
$ 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 Я погуглил несколько jq примеров и обновил свой ответ на их основе.
Вы также можете быстро реализовать 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
Используйте 'jq' для разбора JSON