-1

I have the regex expression "myname"(?:(?:.*\n)+).*tree_ish = "(.*)",, that works fine for itself (tested in https://regex101.com/) with:

    name = "myname",
    dummy1 = 2345,
    dummy2 = "dummy",
    tree_ish = "bc59c4f7c7cf4d0b969a3f405a4a5b7fee22ae96",

Now I want to use that regex expression in sed to replace the one captioning group but cannot figure out the proper escaping. I tried to escape all \().*+ but somehow neither permutation did work. And sadly using sed is not as easy as:

sed -i 's|"myname"(?:(?:.*\n)+).*tree_ish = "(.*)",|rEpLaCe|' myfile

Does anyone know what the correct escaping would look like for replacing bc59c4f7c7cf4d0b969a3f405a4a5b7fee22ae96 with rEpLaCe?

Expected output:

    name = "myname",
    dummy1 = 2345,
    dummy2 = "dummy",
    tree_ish = "rEpLaCe",
abergmeier
  • 11,287
  • 10
  • 49
  • 88
  • an increasingly common mistake being made these days... different tools use different regex flavors... sed supports BRE and ERE and even that differs between GNU sed and other sed implementations... regex101 supports PCRE and similar regex flavors... BRE/ERE don't have non-greedy regex, lookarounds, named/unnamed capture groups and so on... and finally sed works line by line by default, so you need something more to replace across lines... please add expected output for given sample – Sundeep Jun 06 '17 at 10:33
  • Ok, added expected output. – abergmeier Jun 06 '17 at 10:38
  • can there be multiple lines between `myname` and `tree_ish`? or they always consecutive lines? – Sundeep Jun 06 '17 at 10:39
  • There can be multiple lines between them. – abergmeier Jun 06 '17 at 10:39
  • then it would be wise to edit the question to show 2-3 sample with multiple lines between them and expected output for that... as I understand it, you want to find a line containing `"myname"` and then replace content between quotes in line containing `tree_ish` – Sundeep Jun 06 '17 at 10:41

1 Answers1

2

awk is better suited here

$ awk '/"myname"/{f=1} /tree_ish/ && f{sub(/"[^"]+"/,"\"rEpLaCe\"");f=0} 1' ip.txt 
    name = "myname",
    dummy1 = 2345,
    dummy2 = "dummy",
    tree_ish = "rEpLaCe",
  • /"myname"/{f=1} set a flag if line contains "myname"
  • /tree_ish/ && f if line contains tree_ish and flag is set
    • sub(/"[^"]+"/,"\"rEpLaCe\"") change contents between double quotes to "rEpLaCe"
    • f=0 clear the flag
  • 1 idiomatic way to print the input line, including any changes made
  • there are lot of assumptions made here like only one double quoted value, no anchors used, etc. Change them accordingly


If PCRE is more comfortable, then probably use

$ perl -0777 -pe 's/"myname".*?tree_ish\h*=\h*"\K[^"]+(?=")/rEpLaCe/sg' ip.txt 
    name = "myname",
    dummy1 = 2345,
    dummy2 = "dummy",
    tree_ish = "rEpLaCe",
Sundeep
  • 19,273
  • 2
  • 19
  • 42
  • Thanks for the suggestion. That might work but anything beyond regular expression is not maintainable. – abergmeier Jun 06 '17 at 10:53
  • @abergmeier can you clarify `not maintainable`? – Sundeep Jun 06 '17 at 10:54
  • `not maintainable` as I have no coworker that has deep knowledge in awk. Without that it is non-obvious how that string works. Forcing them to learn awk just for a small script is unreasonable. Most do know regular expressions (PCRE), though. – abergmeier Jun 06 '17 at 10:57