0

I need to replace a couple values in a minified javascript file with sed. The OS is alpine Linux.

I'm trying to workout a generic regex which will find foo: and any characters until the next , like so: foo:____ and replace with foo:"bar" or foo:!0 whatever the value in the variable might be. This script needs to work all the time. It shouldn't depend on was is coming after the : ( meaning whatever the value from the property is).

Here are the first couple characters from the file

(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{3:function(l,n,t){l.exports=t("zUnb")},AytR:function(l,n,t){"use strict";t.d(n,"a",function(){return e});var e={appVersion:"1.4-beta",buildNr:"123.123",production:!0,tracking:!0,apiHost:"/api/",foo:""}},Cdxl:function(l,n,t){"use strict";t.d(n,"a",function(){return a});

Here is my start it isn't generic at all ...

APP_VERSION='"1.4-beta"'
BUILD_NR='"20190118.1"'
PRODUCTION="!"
TRACKING="!0"
API_HOST='"/api/"'
FOO='"bar"'

# demo for the first 3 variables 
sed -i "s/appVersion:[\"0-9A-Za-z.]*/appVersion:${APP_VERSION}/;s/buildNr:[\"0-9A-Za-z.]*/buildNr:${BUILD_NR}/;s/production:[!0-9A-Za-z.]*/production:${PRODUCTION}/" path/to/js-file.js

I tried for hours - Any suggestions are more than welcome.

Thanks in advance!

stevo
  • 2,164
  • 4
  • 23
  • 33

1 Answers1

0

You can use the g modifier on the end of the regex to replace all occurrences of pattern match.

General Example

{one:"1",two:"2",three:"3",one:"one",plz:"nope"}

I want to replace everything after one with "42". Without the global modifier, I get this result:

$ sed -E 's/one:[^,]+/one:"42"/' foo.txt
{one:"42",two:"2",three:"3",one:"one",plz:"nope"}

Note how the second instance of one: has not changed. Now with the g modifier:

$ sed -E 's/one:[^,]+/one:"42"/g' foo.txt
{one:"42",two:"2",three:"3",one:"42",yas:"nope"}

That replaces all occurrences.

Your specific case

Stick this into a file, maybe called replacer.sh:

#!/usr/bin/env bash

# declare `swap` to be an associative array
declare -A swap

swap[appVersion]='"1.4-beta"'
swap[buildNr]='"20190118.1"'
swap[production]="!"
swap[tracking]="!0"
swap[apiHost]='"\/api-2\/"'
swap[foo]='"bar"'

FILE=$1

for key in ${!swap[@]}; do sed -E -i 'bak' "s/${key}:[^,]+/${key}:${swap[${key}]}/g" $FILE; done

Change the keys and values in the swap variable to be what you need. Case matters, and escape any backslashes in the values.

If you need to replace more things, you can simply add more key/value pairs. The loop will iterate over all keys, applying the changes in order.

sed can automatically create backup files with the -i flag; I think these might get blown away during each iteration of the loop—be careful here.

Run program like so: $ ./replacer.sh filename.js

Hope this helps!

Ashton Wiersdorf
  • 1,865
  • 12
  • 33
  • Looping over a file multiple times to do `sed -i` on each iteration is an antipattern. You want to feed `sed` a more complex script which performs all the substitutions you want, and only process the file once. – tripleee Jan 21 '19 at 05:47
  • More fundamentally, the real problem here is that `sed` is not a good tool for implementing a completely general JSON parser. A correct script should understand when JSON occurs quoted inside a JSON string, for example. – tripleee Jan 21 '19 at 05:48
  • @tripleee You are definitely correct about the JSON parsing—Your answer is much better. Stevo asked specifically about sed however. Thanks for the point about repeated uses of `sed -i`! I’m no Bash expert, and I’m glad to learn. :) – Ashton Wiersdorf Jan 21 '19 at 16:40
  • Something like this maybe? https://stackoverflow.com/a/22746932/874188 – tripleee Jan 21 '19 at 16:49