I'm using Windows 10 x64, Powershell Core 7.2.6, and /usr/bin/sed (GNU sed) 4.8
installed with Git for Windows. No WSL at all.
I have a .env
file like this.
ENDPOINT="localhost:3000"
and I need to change it to:
ENDPOINT=""
So I'm using this powershell command:
sed -i -e 's/ENDPOINT="localhost:3000"/ENDPOINT=""/g' .env
but it doesn't change the file and there is no error at all.
If I use this instead it works:
sed -i -e 's/ENDPOINT/THIS_WORKS/g' .env
Why?
Maybe the issues are the "
double quotes?
I tried with `" and "" too. No luck!
I tried the suggestion to use:
sed -i -e 's/ENDPOINT=\"localhost:3000\"/ENDPOINT=\"\"/g' .env
but it errors with:
/usr/bin/sed: -e expression #1, char 67: unknown option to `s'
I also tried to reproduce the problem with:
'a', 'ENDPOINT="localhost:3000"', 'b' | sed -e 's/ENDPOINT=\"localhost:3000\"/ENDPOINT=\"\"/g'
The result is:
a
ENDPOINT="localhost:3000"
b
CodePudding user response:
To work around a long-standing PowerShell bug present up to at least 7.2.x,
"
chars. embedded in arguments passed to external programs must manually be escaped as\"
- see this answer- The last two commands in your question do do that, which is normally enough, for most external CLIs.
Additionally, in your specific scenario you need to work around a quirk? bug? in the
sed.exe
implementation that ships with Git for Windows by ensuring that your-e
argument (thesed
script) contains at least one (insignificant) space (sic):
# Note the manually escaped " chars. (\") AND
# the space right after the opening ' char.
# Result is now as expected: 'a', 'ENDPOINT=""', 'b'
'a', 'ENDPOINT="localhost:3000"', 'b' |
sed -e ' s/ENDPOINT=\"localhost:3000\"/ENDPOINT=\"\"/g'
The reason that the space makes a difference is that it causes PowerShell to enclose the argument in "..."
behind the scenes when it builds the command line ultimately used for execution, which in the absence of spaces it does not do. Inexplicably, when the sed.exe
implementation that comes with Git for Windows sees the unquoted token s/ENDPOINT=\"localhost:3000\"/ENDPOINT=\"\"/g
on its command line, it doesn't recognize it correctly, even though it should (it should be equivalent to the double-quoted form, "s/ENDPOINT=\"localhost:3000\"/ENDPOINT=\"\"/g"
).
There are alternative workarounds:
Bypass the problem with
"
characters by using ased
escape sequence to represent them instead, namely\x22
:'a', 'ENDPOINT="localhost:3000"', 'b' | sed -e 's/ENDPOINT=\x22localhost:3000\x22/ENDPOINT=\x22\x22/g'
Use
--%
, the stop-parsing token to explicitly control the quoting on the command line thatsed.exe
sees. Caveat:--%
has significant limitations, notably the inability to (directly) incorporate PowerShell variables and expressions in the command - see this answer.# Note: Everything after --% is copied as-is to the command # line used behind the scenes to invoke sed.exe 'a', 'ENDPOINT="localhost:3000"', 'b' | sed -e --% "s/ENDPOINT=\"localhost:3000\"/ENDPOINT=\"\"/g"