1

In a package.json, I'm trying to replace that:

  "main": "lib/index.js",
  "types": "lib/index.d.ts",

By that :

 "main": "./index.js",
 "types": "./index.d.ts",

So I wrote a simple script that replaces the string pattern by a dot, like so:

sed 's/lib\//.\//g' package.json

It works when I type it in the terminal.

But when it doesn't run properly when inserted in a package.json script.

package.json:

"build": "tsc && cp package.json lib/ && cd lib && sed 's/lib\//.\//g' package.json && npm publish ./lib"

Output:

 sed: 1: "s/lib//.//g": bad flag in substitute command: '.'

It keeps replacing the escaping backslash by forward slash.

How can I make it work ?

JSharles
  • 565
  • 1
  • 5
  • 16
  • 2
    It's usually much easier if you use a `sed` delimiter other than `/` when `/` is one of the characters you want to match on. `sed 's,lib/,./,g'` for example – Ted Lyngmo Jul 05 '22 at 17:13
  • Are you trying to modify `package.json` from a script defined within `package.json`? – jordanm Jul 05 '22 at 17:14
  • I copy it first in another location and then I modify the copy. – JSharles Jul 05 '22 at 17:16
  • @JSharles Did you try the version I suggested? – Ted Lyngmo Jul 05 '22 at 17:21
  • @TedLyngmo well, it throws me the amended version in terminal, but the file is not modified... I'm trying to understand – JSharles Jul 05 '22 at 17:27
  • 1
    Sure, you don't modify the file. Do `sed -i 's,lib/,./,g' package.json` if you want to make modifications to the file you copied to `lib`. I wonder aboute the following `npm publish ./lib` though, since you've already `cd`:d into `lib`. – Ted Lyngmo Jul 05 '22 at 17:28
  • @TedLyngmo It throws : sed: 1: "package.json": extra characters at the end of p command – JSharles Jul 05 '22 at 17:34
  • @JSharles Are you sure that your command line is quoted properly? There is no `p` command in what I wrote. `package.json` is the only thing containing a `p`. Can you paste the exact `build` line that gives that error? – Ted Lyngmo Jul 05 '22 at 17:39
  • Adding a -e like so : sed -i -e 's,lib/,./,g' lib/package.json make it work. But it creates another copy of the file with this name: package.json-e – JSharles Jul 05 '22 at 17:40
  • `sed -i -e 's,lib/,./,g' lib/package.json` seems wrong since you did `cd lib` after copying `package.json` to `lib`. Can you please show the exact and full `build` command? – Ted Lyngmo Jul 05 '22 at 17:41
  • 1
    @TedLyngmo I removed the cd lib in order to follow your pattern. Anyway, thank you you made it work. – JSharles Jul 05 '22 at 17:43
  • This is not in any way specific to bash, or zsh, or any other shell -- you'd have the same problem if you were directly invoking `sed` even with no shell at all. As such, there's no reason to tag it `bash` or `shell` or `zsh`; the only appropriate tag is `sed`. – Charles Duffy Jul 05 '22 at 17:46
  • 2
    ...that said, for editing JSON, you should really be using a syntax-aware tool like `jq`. `sed` can easily transform a valid document to an invalid one; whereas unless you tell jq you want it to emit raw output, it is literally incapable of generating invalid syntax as output (unless you count a stream of documents where only one document is expected as an invalid-syntax case). – Charles Duffy Jul 05 '22 at 17:47
  • 2
    You probably don't want to use `sed` to process JSON at all. Try something like `jq '.[] |= sub("lib"; ".")' package.json > tmp.json && mv tmp.json package.json` instead. – chepner Jul 05 '22 at 17:48
  • @CharlesDuffy Perhaps [tag:json] would be appropriate instead of the other tags since it's the json parser that "eats" the backslash aimed for `sed`? – Ted Lyngmo Jul 05 '22 at 17:50
  • 1
    @chepner Or instead of `cp package.json lib/package.json && cd lib && jq ...` then `jq '.[] |= sub("lib"; ".")' package.json > lib/package.json`? – Ted Lyngmo Jul 05 '22 at 17:51
  • @CharlesDuffy Thank you for the tool, I didn't know. But since jq needs to be installed, what if I need to share the script ? – JSharles Jul 05 '22 at 17:52
  • @JSharles You can do the same in [tag:python] with 1-3 lines of code too and [tag:python] is most probably installed already. – Ted Lyngmo Jul 05 '22 at 17:53
  • 1
    @TedLyngmo Oh nice, I never used python. That's an opportunity to start I guess. – JSharles Jul 05 '22 at 17:58
  • BTW, `sed -i -e ...` creating files with `-e` on the end means you're using BSD tools (like those from MacOS), instead of more Linux-typical GNU ones. For BSD sed, you want an empty string passed after `-i`, so `sed -i '' -e ...` – Charles Duffy Jul 05 '22 at 18:11
  • Why is this tagged _zsh_? – user1934428 Jul 06 '22 at 07:06
  • @user1934428 it's a misunderstanding on my part – JSharles Jul 06 '22 at 08:02

1 Answers1

1

You make changes to a document and \ has special meaning in json. It's an escape character there too. You therefore need to escape your escape character:

s/lib\\//.\\//g

or give the json parser the unicode value for backslash:

s/lib\u005c//.\u005c//g

or simpler, don't use a forward slash as the delimiter in when it's one of the characters that you want to match on:

sed 's,lib/,./,g'

Note that you are not actually modifying the document. To do that, add the sed option -i.

sed -i 's,lib/,./,g' package.json

Note: If you are using BSD tools, you need to add an empty argument to -i:

sed -i '' 's,lib/,./,g' package.json

or avoid that problem by not copying the document followed by cd lib. You could sed the original and direct the output to the new file instead:

sed 's,lib/,./,g' package.json > lib/package.json
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108