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?

  • 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? – ilkkachu Aug 7 '16 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 – Borys Aug 7 '16 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. – cas Aug 7 '16 at 22:37
  • it's not doable – Borys Aug 7 '16 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... – ilkkachu Aug 7 '16 at 22:43
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"}
  • Brilliant! That's exactly what I wanted! Thank you! – Borys Aug 7 '16 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"}
  • 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. – cas Aug 8 '16 at 12:18
  • thanks, but it's not json, it's python dictionary. – Borys Aug 12 '16 at 12:13
  • @Borys Why not use Python then? – Kusalananda Aug 12 '16 at 12:14
  • I would love to, but I don't know the language and I'm working on code written by somebody else – Borys Aug 12 '16 at 12:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.