2017-01-06 8 views
2

Я хочу изменить файл JSON с помощью командной строки Linux.Изменение JSON с помощью jq

Я пробовал эти шаги:

[[email protected]]# INPUT="dsa" 
[[email protected]]# echo $INPUT 
dsa 
[[email protected]]# CONF_FILE=test.json 
[[email protected]]# echo $CONF_FILE 
test.json 
[[email protected]]# cat $CONF_FILE 
{ 
    "global" : { 
    "name" : "asd", 
    "id" : 1 
    } 
} 
[[email protected]]# jq -r '.global.name |= '""$INPUT"" $CONF_FILE > tmp.$$.json && mv tmp.$$.json $CONF_FILE 
jq: error: dsa/0 is not defined at <top-level>, line 1: 
.global.name |= dsa 
jq: 1 compile error 

Желаемая выход:

[[email protected]]# cat $CONF_FILE 
    { "global" : { 
    "name" : "dsa", 
    "id" : 1 } } 
+3

немного подсказка, не входите в систему как root, чтобы делать работу. – Kent

ответ

4

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

В вашем конкретном случае, с использованием одного двойных кавычках со встроенными \" случаев убежал, вероятно, простейший:

jq -r ".global.name = \"$INPUT\"" "$CONF_FILE" > tmp.$$.json && mv tmp.$$.json "$CONF_FILE" 

В целом, однако, chepner's helpful answer показывает более надежную альтернативу встраивания переменной оболочки ссылки непосредственно в сценарии: Использование --arg варианта передать значение в качестве jqпеременной позволяет одинарного quotin g сценарий, который предпочтительнее, поскольку он позволяет избежать путаницы в отношении того, какие элементы расширены оболочкой вверх и устраняет необходимость экранирования $ экземпляров, которые должны быть переданы до jq.

также:

  • Просто = достаточно присвоить значение; в то время как операционный оператор |= также работает так же, как и в случае с =, поскольку RHS является литералом , а не выражением, ссылающимся на LHS - см. the manual.
  • Вы должны регулярно дублировать ссылки на shell-переменные, и вам следует избегать использования имен переменных в верхнем регистре для avoid conflicts with environment variables and special shell variables.

Что касается , почему ваш процитировать не работал:

'.global.name |= '""$INPUT"" состоит из следующих лексем:

  • Строка буквальным .global.name |= (из-за одного цитирую)
  • Строковый литерал "" - т.е.Пустая строка - котировки будут удалены оболочкой, прежде чем jq видит сценарий
  • An без кавычек ссылки на переменную $INPUT (что делает его стоимость, подлежащего софистика и подстановка).
  • Другой экземпляр литерала "".

С вашим значением образца, jq закончил видеть следующую строку в качестве сценария:

.global.name |= dsa 

Как вы можете видеть, двойные кавычки не хватает, в результате чего jq интерпретировать dsa как имя функции, а не строковый литерал, и поскольку никакой аргумент не передавался (несуществующей) функции dsa, сообщение об ошибке jq ссылалось на него как dsa/0 - функция без аргументов (0).

1

Использование jq с прямой вперед фильтр, должен сделать это для вас.

.global.name = "dsa" 

т.е.

jq '.global.name = "dsa"' json-file 
{ 
    "global": { 
    "name": "dsa", 
    "id": 1 
    } 
} 

Вы можете играть с вашими JSon-фильтрами, here.

+1

'| =' не проблема; цитата была. – chepner

+0

@chepner: не поймал его раньше. – Inian

+1

Также обратите внимание, что _filter_ - очень широкое понятие в 'jq' (для цитаты из [manual] (https://stedolan.github.io/jq/manual/):« Программа jq - это «фильтр»: это берет вход и производит выход. '), тогда как представляющая интерес функция здесь является _assignment_. – mklement0

4

Это намного проще и безопаснее передать значение с помощью опции --arg:

jq -r --arg newname "$INPUT" '.global.name |= $newname' "$CONF_FILE" 

Это гарантирует, что точное значение $INPUT используется и цитируемый в качестве значения JSON.

Смежные вопросы