0

I want to batch replace strings recursively inside a folder, and I have settled with using Perl. I would like to see if there is a solution which requires less dependency and work across platforms.

For listing files, I can use anything from ls to find to ag, rg. Lemme demonstrate my problem with ls.

ls | xargs -I '{}' ed -s {} <<< $'='

I will get this:

Is a directory newline appended =: No such file or directory

As the pipe is used for passing filenames to xargs, and streams (here-string) seems not working (How can heredocs be used with xargs?). I wonder if it is possible to use xargs with ed.

My concern is cross platform and in fact that command will be put inside package.json for npm run global_replace. We are wondering if there are solutions other than introducing gulp-replace and gulp just for this task.

Sunny Pun
  • 726
  • 5
  • 14
  • What command are you trying to run in ed? `$'='` is reduced to just `=` by the shell (ANSI-C quoting) and will print the line number of the current line, which is the last one. – Benjamin W. Nov 09 '18 at 05:16
  • @BenjaminW. Sorry for the bad example. Another one may be `$'2,5d\nw'` which is to delete those lines and save. My point was to demonstrate that herestring doesn't work. – Sunny Pun Nov 09 '18 at 08:10

2 Answers2

0

Try this solution:

find . -name "*" | xargs sed -i 's/regex/replacestring/g'
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
Vinod Kumar
  • 562
  • 5
  • 12
  • Thanks! I once thought that `sed` would be platform-independent enough. However `sed` was different for "natural" Linux setup and MacOS, and that even with `sed -i '' '...'` there are illegal bytes which needs `LC_ALL=C` which converts line endings. Hope that `ed` behaves better. – Sunny Pun Nov 09 '18 at 08:13
0

After some investigation, using herestring is not completely impossible:

find ... | xargs -0 -I{} sh -c 'ed -s "$1" <<< '"$',s/foo/bar/g\nw'" -- {}

And in package.json, I have to escape each ", so now we can run npm run replace. The exit code will be status 1 and it does not look good although it works.

Many thanks to @Benjamin.W for his help in the comments!

Sunny Pun
  • 726
  • 5
  • 14
  • 1
    You can move parts of the argument to `sh -c` to be double quoted and the rest single quoted, like this: `sh -c 'ed -s "$1" <<< '"$',s/foo/bar/g\nw'"`. Make sure to quote `$1`, or the whole benefit of `-print0` and `xargs -0` is lost again. – Benjamin W. Nov 09 '18 at 15:14
  • "newline appended" indicates that the file didn't have a newline on the last line and ed added one. Some editors create files like that, but they shouldn't, according to POSIX. – Benjamin W. Nov 09 '18 at 15:15