Stefan van de Vooren
Stefan van de Vooren

Reputation: 2717

Multiline regular expression shell script

I need to replace a hash for a file in manifest. My problem is I don't know the original hash, only the new one.

mainfest:

[
  {
    "file": "bundle.js",
    "hash": "0a4c61f0cf23ca1fd39c411140941cd5"
  },
  {
    "file": "0fdbe5712e250dac1fa5930395f65a27.jpg",
    "hash": "0fdbe5712e250dac1fa5930395f65a27"
  }
]

As you could see, in the manifest (JSON) file name and hash are bundled in an object.

I want to change the hash file for the bundle.js with a new one. I use below shell script with sed and regular expression to replace the hash.

shell script:

#!/bin/sh
NEW_HASH="$(md5 < ./scripts/bundle.js)"
sed 's/\({"file": "bundle.js","hash": "\).*\("}\)/\1'$NEW_HASH'\2/g' chcp.manifest

Only I don't know how to match the multiple lines. Mine regex matches only a single line

{"file": "bundle.js","hash": "0a4c61f0cf23ca1fd39c411140941cd5"}

and not

{
   "file": "bundle.js",
   "hash": "0a4c61f0cf23ca1fd39c411140941cd5"
 }

I tried something like:

sed 's/\({"file": "bundle.js",\n   "hash": "\).*\("\n   }\)/\1'$NEW_HASH'\2/g' chcp.manifest

but \n doesn't seam to work for matching a new line

Upvotes: 0

Views: 79

Answers (1)

larsks
larsks

Reputation: 311606

Trying to parse a structured format like JSON (or XML, etc) with something like sed or awk is tricky and never as robust as using a tool actually designed to parse the data with which you're working.

Your task would be relatively trivial using Python or Ruby or Perl or something else with a JSON parser. For shell scripts, you may want to investigate the jq command, which is available as a package for most distributions.

Using jq, you could use the technique described in this document, which would boil down to:

NEW_HASH="$(md5 < ./scripts/bundle.js)"
jq 'map(if .file == "bundle.json" 
        then . + {"hash": "'"$NEW_HASH"'"}
        else . 
        end)' chcp.manifest

That would generate the new document on stdout; you could obviously save that to a file and then rename that to replace the original.

Upvotes: 2

Related Questions