2016-01-29 3 views
2

У меня есть вопрос jq. Учитывая файл file.json содержащий:jq: как обновить значение на основе соответствия подстроки?

[ 
    { 
    "type": "A", 
    "name": "name 1", 
    "url": "http://domain.com/path/to/filenameA.zip" 
    }, 
    { 
    "type": "B", 
    "name": "name 2", 
    "url": "http://domain.com/otherpath/to/filenameB.zip" 
    }, 
    { 
    "type": "C", 
    "name": "name 3", 
    "url": "http://otherdomain.com/otherpath/to/filenameB.zip" 
    } 
] 

Я ищу, чтобы создать еще один файл JQ с URL изменен только, если значение URL, соответствует некоторому шаблону. Например, я хочу, чтобы обновить любой URL, соответствующим шаблон:

http://otherdomain.com.*filenameB.* 

до некоторой фиксированной строки, таких как:

http://yetanotherdomain.com/new/path/to/filenameC.tar.gz 

с результирующим: гавань JSON

[ 
    { 
    "type": "A", 
    "name": "name 1", 
    "url": "http://domain.com/path/to/filenameA.zip" 
    }, 
    { 
    "type": "B", 
    "name": "name 2", 
    "url": "http://domain.com/otherpath/to/filenameB.zip" 
    }, 
    { 
    "type": "C", 
    "name": "name 3", 
    "url": "http://yetanotherdomain.com/new/path/to/filenameB.tar.gz" 
    } 
] 

I 't получил далеко даже на возможность найти URL-адрес, не говоря уже об обновлении. Это, насколько я получил (неправильные результаты и не поможет мне с вопросом обновления):

% cat file.json | jq -r '.[] | select(.url | index("filenameB")).url' 
http://domain.com/otherpath/to/filenameB.zip 
http://otherdomain.com/otherpath/to/filenameB.zip 
% 

Любые идеи о том, как получить путь к ключу, который имеет значение, соответствующее регулярное выражение? И после этого, как обновить ключ с некоторым новым значением строки? Если существует несколько совпадений, все они должны быть обновлены с тем же новым значением.

ответ

1

Хорошая новость заключается в том, что есть простое решение проблемы:

map(if .url | test("http://otherdomain.com.*filenameB.*") 
    then .url |= sub( "http://otherdomain.com.*filenameB.*"; 
      "http://yetanotherdomain.com/new/path/to/filenameC.tar.gz") 
    else . 
    end) 

Не очень хорошие новости в том, что это не так легко объяснить, если вы не понимаете ключ сообразительность здесь - «| = ". В нем много документации по jq, поэтому я просто укажу, что он похож на семейство операторов + = в семействе языков программирования C.

В частности, .url |= sub(A;B) - это как .url = (.url|sub(A;B)). Таким образом, обновление выполняется «на месте».

+0

Спасибо за часть обновления ответа. Оно работает. Как мне получить путь к найденному элементу? Я мог бы захотеть этого, если бы я хотел сохранить путь, чтобы позже в сценарии bash я мог использовать этот путь для обновления этого конкретного элемента. Мне действительно нужны две отдельные операции: найдите путь к элементу, который соответствует шаблону, и обновите элемент с новым значением. –

+0

@SteveAmerige - Я не совсем уверен, что ваш дополнительный вопрос (или вопросы) есть (или есть), но вы можете читать на '..' или, возможно, задать отдельный SO" вопрос ". – peak

+0

Спасибо, я сделаю это. –

1

Вот решение, которое определяет пути к членам URL-адрес с tostream и выберите, а затем обновляет значения с помощью уменьшить и setpath

"http://otherdomain.com.*filenameB.*"      as $from 
| "http://yetanotherdomain.com/new/path/to/filenameC.tar.gz" as $to 

| reduce (tostream | select(length == 2 and .[0][-1] == "url")) as $p (
     . 
    ; setpath($p[0]; $p[1] | sub($from; $to)) 
) 
+0

Блестящий! Большое спасибо за помощь! –

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