How to properly escape quotes in powershell v2?
How do you properly escape quotes in powershell v2 (called from within a batch file)?
I have tried:
powershell -Command "(gc file1.txt) -join "`n" | Out-File file2.txt"
and
powershell -Command "(gc file1.txt) -join ""`n"" | Out-File file2.txt"
and
powershell -Command "(gc file1.txt) -join '"`n`" | Out-File file2.txt"
but they all fail.
Editor's note: The purpose of the command is to transform Windows CRLF line breaks to Unix LF-only ones, so as to create a file that will be processed on Linux.
Solution 1:
From a batch file (cmd.exe
), you must \
-escape embedded "
instances
(even though PowerShell-internally it is `
(the backtick) that serves as the escape character):
As wOxxOm points out in a comment on the question, in Windows PowerShell using """
to embed a single "
is also an option.
However, given that most command-line utilities support \"
, \"
is easier to remember. However, both """
and \"
can break on the cmd.exe
side, in which case "^""
(sic) is required (""
in PowerShell (Core) 7+).
powershell -Command "(gc file1.txt) -join \"`n\" | Set-Content -NoNewLine file2.txt"
Note:
-
Set-Content -NoNewline
requires PSv5+. -
Set-Content
writes "ANSI"-encoded files by default (e.g., based on code page Windows-1252 on US-English systems); use the-Encoding
parameter to change that.- Since you're only dealing with strings,
Set-Content
is preferable toOut-File
, which is only needed if you have non-string objects that must have PowerShell's default formatting applied to them first.
- Since you're only dealing with strings,
-
Consider using
powershell -NoProfile ...
to suppress loading of PowerShell's profile files, both for faster execution and for a more predictable execution environement.
PSv2 solution:
Unfortunately, prior to PSv5, only the Write-Host
cmdlet supports the -NoNewline
parameter (introduced in v2), which is of no help here, so the .NET framework must be used:
powershell -Command "[IO.File]::WriteAllText(\"$PWD/file2.txt\", ((gc $PWD/file1.txt) -join \"`n\") + \"`n\")"
Note the need to use path prefix $PWD
explicitly, because the .NET Framework's current directory typically differs from PowerShell's.
Also, the output file's encoding will be UTF-8, without a BOM, but you can pass a different encoding as the 3rd argument to [IO.File]::WriteAllText()
, such as [System.Text.Encoding]::Default
to match Set-Content
's default behavior (as of Windows PowerShell v5.1).
Optional reading: platform-specific line breaks "`n"
vs. "`r`n"
vs. [Environment]::Newline
Implicit choice of newlines (line breaks):
-
when reading, PowerShell accepts LF-only (Unix-style) and CRLF (Windows-style) newlines (line breaks) interchangeably.
-
when writing (e.g., when sending an array of lines / objects to a file with
>
/Out-File
/Set-Content
), PowerShell uses the platform-appropriate newline sequence.
Note, however, that any newline sequences embedded in a given string input object are sent to the file as-is.
As for escape sequences / constants:
-
[Environment]::Newline
contains the platform-appropriate newline. -
"`n"
is always just LF (\n
)-
as evidenced by
"`n".Length
returning1
and[char] 10 -eq [char] "`n"
returning$True
(10
is the decimal Unicode/ASCII code point of LF). -
The documentation isn't explicit about this:
Get-Help about_Special_Characters
mentions "new line" and "line break", without mentioning what specific character [sequence] that represents. (As mentioned, LF by itself is just as valid a line break as CRLF is in PowerShell).
-
-
Therefore, to create CRLF sequences, you must use
"`r`n"
. -
If you need to match newlines in either format, you can use regex
'\r?\n'
, with operators such as-match
,-replace
, and-split
As for multi-line string literals in scripts (including here-documents):
- They reflect their source file's newline style. That is, if your script uses CRLF newlines, so will the newlines embedded in the multi-line string.
Solution 2:
Here's one way to do it from the PowerShell command line:
(Get-Content Input.txt -Raw) -replace "`r`n","`n" | Out-File Output.txt -Encoding ASCII -NoNewline
As others have noted this is a PowerShell v5 solution (-Raw
appeared in v3, and -NoNewline
appeared in v5).
Here's a PowerShell v2 version of the same thing:
$content = [IO.File]::ReadAllText("C:\Path\Input.txt") -replace "`r`n","`n"
[IO.File]::WriteAllText("C:\Path\Output.txt", $content)
(The paths are needed because the .NET methods don't use PowerShell's "current location".)