Both of these commands doesn't create multiple line text:
Set-Content .\test.md 'Hello`r`nWorld'
Set-Content .\test.md 'Hello\r\nWorld'
Only this can
Set-Content .\test.md @("Hello`nWorld")
Do you know why is that?
CodePudding user response:
Escape sequences such as
`r`n
only work inside"..."
, i.e, expandable (interpolating) strings.- By contrast,
'...'
strings are verbatim strings that do not interpret their contents - even`
instances are used as verbatim (literally).
- By contrast,
Only
`
(the so-called backtick) serves as the escape character in PowerShell, not\
.- That is, in both
"..."
and'...'
strings a\
is a literal. - (However,
\
is the escape character in the context of regexes (regular expressions), but it is then the .NET regex engine that interprets them, not PowerShell; e.g.,"`r" -match '\r'
is$true
: the (interpolated) literal CR char. matched its escaped regex representation).
- That is, in both
As for what you tried:
It is the fact that
"Hello`nWorld"
in your last command is a"..."
string that made it work.- By contrast, enclosing the string in
@(...)
, the array-subexpression operator, is incidental to the solution. (Set-Content
's (positionally implied)-Value
parameter is array-valued anyway (System.Object[]
), so even a single string getting passed is coerced to an array).
- By contrast, enclosing the string in
Finally, note that
Set-Content
by default adds a trailing, platform-native newline to the output file; use-NoNewLine
to suppress that, but note that doing so also places no newline between the (string representations of) multiple input objects, if applicable (in your case there's only one).
Therefore (note the -NoNewLine
and the trailing `n
):
Set-Content -NoNewLine .\test.md "Hello`nWorld`n"
Optional reading: design rationale for PowerShell's behavior:
Why doesn't PowerShell use the backslash (
\
) as the escape character, like other languages?
Because PowerShell must (also) function on Windows (it started out as Windows-only), use of \
as the escape character - as known from Unix (POSIX-compatible) shells such as Bash - is not an option, given that \
is used as the path separator on Windows.
If \
were the escape character, you'd have to use Get-ChildItem C:\\Windows\\System32
instead of Get-ChildItem C:\Windows\System32
, which is obviously impractical in a shell, where dealing with file-system paths is very common.
Thus, a different character had to be chosen, which turned out to be `
, the so-called backtick: At least on US keyboards, it is easy to type (just like \
), and it has the benefit of occurring rarely (as itself) in real-world strings, so that the need to escape it rarely arises.
Note that the much older legacy shell on Windows, cmd.exe
, too had to pick a different character: ^
, the so-called caret.
Why doesn't it use single quote and double quote interchangeably, like other languages?
Different languages made different design choices, but in making "..."
strings interpolating, but '...'
strings not, PowerShell did follow existing languages here, namely that of POSIX-compatible shells such as Bash.
Unlike the latter it also supports embedding verbatim '
inside '...'
, escaped as ''
(e.g., '6'' tall'
)
Given PowerShell's commitment to backward compatibility, this behavior won't change, especially given how fundamental it is to the language.
Conceptually speaking, you could argue that the aspect of what quoting character a string uses should be separate from whether it is interpolating, so that you're free to choose one of the other quoting style for convenience, while separately controlling whether interpolation should occur.
Thus, hypothetically, PowerShell could have used a separate sigil to make a string interpolating, say $"..."
and $'...'
(similar to what C# now offers, though it notably only has one string-quoting style).
(As an aside: Bash and Ksh do have this syntax form, but it serves a different purpose (localization of strings) and is rarely used in pratice).
In practice, however, once you know how "..."
and '...'
work in PowerShell, it isn't hard to make them work as intended.
See this answer for a juxtaposition of PowerShell, cmd.exe
, and POSIX-compatible shells with respect to fundamental features.