0

I have to replace every string after colon with the same word + underscore + number in following way:

{"first": "1_first", "second": "1_second"} 

Expected results:

{"first": "first_1", "second": "second_1"} {"first": "first_20", "second": "second_20"} {"first": "first_33", "second": "second_33"} 

I've succeeded with the first one:

echo '{"first": "first_1", "second": "second_1"}' | sed "s/\( \".*\",\)/ \"first_$j\",/" 

Result is:

{"first": "first_888", "second": "second_1"} 

But have problems with the second one. I suppose that this expression is too greedy:

echo '{"first": "first_1", "second": "second_1"}'|sed "s/\( \".*\)\"}/ \"second_$j\"}/" 

This one cuts too much:

{"first": "second_888"} 

Maybe there is some more elegant way to do this? With one expression instead of 2?

5
  • 1
    what does the "same word" refer to? you have things like "key": "value", do you mean the replacement word should be the key or the value? Commented Aug 7, 2016 at 22:29
  • I need to replace the value and it should be the same as the key name (keeps the same all the time) plus _NUMBER. So the value looks after whole operation like this: key_23 Commented Aug 7, 2016 at 22:32
  • 2
    use jq or jsonpipe or some other json parser for modifying or extracting data from json. regexps don't work reliably for json for the same reason that they don't for xml or html: Don't parse XML or HTML with regular expressions. It doesn't work. Commented Aug 7, 2016 at 22:37
  • it's not doable Commented Aug 7, 2016 at 22:41
  • While I don't disagree with using a real parser for actual work, that page seems written as a horrible rant and likely just pushes people away from what it's trying to tell them to do... Commented Aug 7, 2016 at 22:43

2 Answers 2

1

I'm not sure if this is what you want, replacing the values with strings from the keys. Works as long as you don't have (escaped) quotes within the keys or values. If you do, or even might, better use a real parser.

$ num=42 $ echo '{"foo": "xxx", "bar": "yyy"}' | \ sed -E 's/"([^"]*)": "[^"]*"/"\1": "\1_'$num'"/g' {"foo": "foo_42", "bar": "bar_42"} 
1
  • Brilliant! That's exactly what I wanted! Thank you! Commented Aug 7, 2016 at 22:49
1

Using jq:

$ cat data.json {"first": "xxx", "second": "xxx"} {"first": "yyy", "second": "yyy"} {"first": "zzz", "second": "zzz"} $ jq 'with_entries(.value = .key + "_42")' data.json { "first": "first_42", "second": "second_42" } { "first": "first_42", "second": "second_42" } { "first": "first_42", "second": "second_42" } 

With a shell variable:

$ number=9 $ jq 'with_entries(.value = .key + "_'$number'")' data.json { "first": "first_9", "second": "second_9" } { "first": "first_9", "second": "second_9" } { "first": "first_9", "second": "second_9" } 

If you prefer compact output:

$ jq -c 'with_entries(.value = .key + "_'$number'")' data.json {"first":"first_9","second":"second_9"} {"first":"first_9","second":"second_9"} {"first":"first_9","second":"second_9"} 
4
  • 1
    +1. and the even more compact json format has no newlines at all unless they're embedded in a quoted string. which are, of course, two of the reasons why modifying json data with regexps is prone to failure - extremely fragile and vulnerable to even minor changes in the json being processed. Commented Aug 8, 2016 at 12:18
  • thanks, but it's not json, it's python dictionary. Commented Aug 12, 2016 at 12:13
  • @Borys Why not use Python then? Commented Aug 12, 2016 at 12:14
  • I would love to, but I don't know the language and I'm working on code written by somebody else Commented Aug 12, 2016 at 12:18

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.