Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace multiline pattern in bash

Tags:

bash

replace

I'd like to replace this:

          }
      ]
  }
  {
      "commits":[

with:

          },

using any command available in bash.

The text above is being parsed from within the bash script itself (not from a file). The "input" is the contents of git log being parsed by 4 different piped commands, which chew and spit the output to a file. The piping looks like that:

git log (...) | paste (...) | tail (...) | awk (...) > output.file

My strategy so far has been to add an extra pipe and a command that replaces a multi-line pattern with a single-line pattern, something like:

git log (...) | paste (...) | tail (...) | awk (...) | 'replace-multiline' (...) > output.file

In other words, I haven't been able to find the right replace-multiline command yet. Maybe you can help me? ;)

What I have tried

I've used three days trying different spins on awk, sed, grep and even perl (the ones that claimed to solve the multiline search & replace challenge). None of them worked on my context. I'm not versed on any of these commands, so I've been prodding in the dark. I'd really appreciate any pointers!

Background

I'm working on a bash script that outputs git log to a valid JSON output (project at github). It works just fine when the script is run from the root of the repository, but I would like to extend it so that it runs from the directory that contains all the repositories, hence outputting the git log for all repositories in JSON format in one single call.

The script, which was moved to the parent directory and made to run on every subdirectory (which are git repos), return the output below (the script was also made to output the repository name as a property within each object item).

The current output:

  {
      "commits":[
          {
              "repository":"repo1",
              "commit_nr":"1",
              /* ... */
          },
          {
              "repository":"repo1",
              "commit_nr":"2",
              /* ... */
          },
          {
              "repository":"repo1",
              "commit_nr":"3",
              /* ... */
          }
      ]
  }
  {
      "commits":[
          {
              "repository":"repo2",
              "commit_nr":"1",
              /* ... */
          },
          {
              "repository":"repo2",
              "commit_nr":"2",
              /* ... */
          },
          {
              "repository":"repo2",
              "commit_nr":"3",
              /* ... */
          }
      ]
  }
  {
      "commits":[
          {
              "repository":"repo3",
              "commit_nr":"1",
              /* ... */
          },
          {
              "repository":"repo3",
              "commit_nr":"2",
              /* ... */
          },
          {
              "repository":"repo3",
              "commit_nr":"3",
              /* ... */
          }
      ]
  }

The wanted output:

  {
      "commits":[
          {
              "repository":"repo1",
              "commit_nr":"1",
              /* ... */
          },
          {
              "repository":"repo1",
              "commit_nr":"2",
              /* ... */
          },
          {
              "repository":"repo1",
              "commit_nr":"3",
              /* ... */
          },
          {
              "repository":"repo2",
              "commit_nr":"1",
              /* ... */
          },
          {
              "repository":"repo2",
              "commit_nr":"2",
              /* ... */
          },
          {
              "repository":"repo2",
              "commit_nr":"3",
              /* ... */
          },
          {
              "repository":"repo3",
              "commit_nr":"1",
              /* ... */
          },
          {
              "repository":"repo3",
              "commit_nr":"2",
              /* ... */
          },
          {
              "repository":"repo3",
              "commit_nr":"3",
              /* ... */
          }
      ]
  }
like image 951
Wallace Sidhrée Avatar asked Feb 14 '26 01:02

Wallace Sidhrée


1 Answers

You want to use perl for this:

$echo "          {
              "repository":"repo2",
              "commit_nr":"3",
              /* ... */
          }
      ]
  }
  {
      "commits":[
          {
              "repository":"repo3",
              "commit_nr":"1",
              /* ... */
          }," | perl -pn -e "BEGIN{undef $/;} s/\}\s*\]\s*\}\s*\{\s*commits:\[/},/g"

yields

          {
              repository:repo2,
              commit_nr:3,
              /* ... */
          },
          {
              repository:repo3,
              commit_nr:1,
              /* ... */
          },

Attention: you might have to add \" around the commit word (this being an echo, the " disappear because they are not escaped by my copy-paste)

like image 194
alestanis Avatar answered Feb 16 '26 18:02

alestanis