Как найти и заменить несколько значений поля с использованием JQ?

На тот случай, если rsync-решение Дэвида Кингса не работает для вас или вы действительно хотите сделать это в bash (зачем вообще), вот как вы могли сделай это:

#!/bin/bash
your_command_to_execute &
myPid=$!
sleepTime=5
while kill -0 "$myPid" 2> /dev/null
do
    # Sleep for the defined time
    sleep $sleepTime
    # And print the time since the script started in seconds
    echo -en "Runtime $SECONDS\033[0K\r"
done

Возможно, вы захотите использовать что-нибудь, чтобы немного лучше отформатировать время.
Также в настоящее время сценарий печатает секунды с момента запуска сценария, а не с момента начала операции cp (если вы хотите изменить это простое, вычтите секунды до цикла из текущего $ SECONDS )

8
19.10.2018, 22:53
3 ответа

Для использования jqна основе функции walk(требуется последняя версия):

jq 'walk(.name?="XXX")' file

Если ваш jqне поддерживает функцию walk, просто определите ее как:

jq '
  # Apply f to composite entities recursively, and to atoms
  def walk(f):
   . as $in
    | if type == "object" then
       reduce keys[] as $key
         ( {};. + { ($key):  ($in[$key] | walk(f)) } ) | f
    elif type == "array" then map( walk(f) ) | f
    else f
    end;
  walk(.name?="XXX")
' file

Кредиты:https://github.com/stedolan/jq/issues/963

10
27.01.2020, 20:10

Операции присваивания jq могут выполнять обновление одновременно в любом количестве местоположений, которое вы можете назвать, и предназначены для такого рода ситуаций. Вы можете использовать

jq '(.. |.name?) |= "XXXX"'
От

до найдите каждое поле с именем «имя» в любом месте и замените значение в каждом сразу на «XXXX» и выведите результирующий объект.

Это всего лишь ..|.a?пример из рекурсивного -документа спуска в сочетании с присваиванием обновления .

Он использует оператор рекурсивного спуска..для поиска каждого отдельного значения в дереве, затем извлекает поле «имя» из каждого из них с помощью .name, подавляет любые ошибки из не -совпадающих значений с ?, а затем обновляет объект во всех этих местах сразу с помощью «XXXX», используя оператор присваивания update -|=, и выводит новый объект.

Это будет работать независимо от файловой структуры и обновлять каждое поле имени везде.


В качестве альтернативы, если файл всегда имеет эту структуру, и вы хотите изменить те конкретные поля «имя», , а не просто любое старое имя, вы также можете просто перечислить их и назначить им как группа тоже:

jq '(.name,.contact[].name,.group[].name) |= "XXXX"'

Выполняет такое же назначение для

  1. поле "имя" объекта верхнего -уровня;
  2. поле "имя" каждого объекта в массиве "контакт"; и
  3. поле «имя» каждого объекта в массиве «группа».

все сразу. Это особенно полезно, если в файле могут быть другие поля имен где-то не связанные, которые вы не хотите изменять. Он находит только три набора названных там местоположений и обновляет их все одновременно.


Если значение является просто литералом, как здесь, тогда простое присваивание с=также работает и экономит вам символ:(..|.name?)="XXXX"-вам также понадобится это, если ваше значение вычисляется на основе всей вершины -объект уровня. Если вместо этого вы хотите вычислить новое имя на основе старого, вам нужно использовать |=. Если я не уверен, что использовать, |=обычно ведет себя немного лучше в крайних случаях.

Если вам нужно выполнить несколько замен , вы можете связать их вместе:

jq '(..|.name?) = "XXXX" | (..|.lname?) = "1234"'

будет везде обновлять поля «имя» и «lname» и выводить весь обновленный объект один раз.


Несколько других подходов, которые могут работать:

  • Вы также можете четко указать, что вы выбираете с помощью

      (..|objects|select(has("name"))).name |= "XXXX"`
    

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

  • Если вы используете разрабатываемую версию jq (маловероятно ), тогда функцияwalkтакже может выполнять эту работу:walk(.name?="XXXX"). Все остальные версии будут работать с последней выпущенной версией 1.5.

  • Альтернативное множественное обновление -может быть

      jq '(..|select(has("name"))?) += {name: "XXXX", lname: "1234"}'
    

который находит все с именем, а затем устанавливает как «имя», так и «lname» для каждого объекта, используя арифметическое обновление -присваивание*=и поведение слияния, которое +имеет для объектов .

15
27.01.2020, 20:10

альтернативно,jtcбазовое решение:

bash $ jtc -w'<name>l+0' -u'"XXX"' your.json 
{
   "contact": [
      {
         "id": 111,
         "name": "XXX"
      }
   ],
   "email": "xxx",
   "group": [
      {
         "lname": "YYY",
         "name": "XXX"
      }
   ],
   "lname": "YYY",
   "name": "XXX",
   "pass": "yyy"
}
bash $ 
1
27.01.2020, 20:10

Теги

Похожие вопросы