这两个命令都不会创建多行文本:
Set-Content .test.md 'Hello`r`nWorld'
Set-Content .test.md 'HellornWorld'
只有这样才能
Set-Content .test.md @("Hello`nWorld")
你知道为什么吗?
-
转义序列(如
`r`n
)仅在"..."
内部工作,即可扩展(插值)字符串。- 相比之下,
'...'
字符串(单引号)是逐字的字符串,不会解释其内容-甚至`
实例也被用作逐字的(字面上)
- 相比之下,
-
只有
`
(即所谓的backtick)用作PowerShell中的转义字符,而不是。
- 也就是说,在
"..."
和'...'
字符串中,是一个文字,即逐字使用
- (但是,
是正则表达式(正则表达式)上下文中的转义符,但它是。NET正则表达式引擎来解释它们,而不是PowerShell;例如。,
"`r" -match 'r'
是$true
:(插值)文字CR字符。匹配其转义的regex表示)
- 也就是说,在
注意:`
-转义也适用于未加引号的令牌,但前提是它们充当命令参数;例如Write-Output line1`r`nline2
等同于"line1`r`nline2"
。
至于您尝试了什么:
-
事实上,上一个命令中的
"Hello`nWorld"
是一个使其工作的"..."
字符串。- 相比之下,将字符串封装在
@(...)
(数组子表达式运算符)中是解决方案的附带。(Set-Content
的(位置隐含的)-Value
参数是数组-无论如何都有值(System.Object[]
),因此即使是传递的单个字符串也会被强制到数组)
- 相比之下,将字符串封装在
-
最后,请注意
Set-Content
默认情况下会向输出文件中添加一个尾随的平台本机换行符;使用-NoNewLine
来抑制这种情况,但请注意,这样做也不会在多个输入对象之间放置换行符(如果适用的话)(在您的情况下,只有一个)。
因此(注意-NoNewLine
和后面的`n
):
Set-Content -NoNewLine .test.md "Hello`nWorld`n"
可选阅读:PowerShell行为的设计原理:
为什么PowerShell不像其他语言那样使用反斜杠(
)作为转义符?
因为PowerShell必须(也)在Windows上运行(它最初只是Windows),所以使用作为转义符(从Unix(POSIX兼容)shell(如Bash)中已知)是而不是选项,因为
在Windows上用作路径分隔符
如果是转义符,则必须使用
Get-ChildItem C:\Windows\System32
而不是Get-ChildItem C:WindowsSystem32
,这在处理文件系统路径非常常见的shell中显然是不切实际的。
因此,必须选择一个不同的字符,结果是`
,即所谓的backtick:至少在美国键盘上,它很容易键入(就像一样),而且它的好处是在现实世界的字符串中很少出现(就像它本身一样),因此很少需要转义。
请注意,Windows上的旧外壳cmd.exe
也必须选择不同的字符:它选择了^
,即所谓的插入符号。
为什么它不像其他语言那样可互换地使用单引号和双引号?
不同的语言做出了不同的设计选择,但在进行"..."
字符串插值时,'...'
字符串而不是,PowerShell遵循了此处的现有语言,即POSIX兼容shell的语言,如Bash。作为对后者的改进,PowerShell还支持在'...'
中嵌入逐字逐句的'
,转义为''
(例如'6'' tall'
)
考虑到PowerShell对向后兼容性的承诺,这种行为不会改变,特别是考虑到它对语言的基础性。
从概念上来说,你可以争辩说,字符串使用的引用字符的方面应该与是否是插值分开,这样你就可以自由地选择一种或另一种引用风格,以方便句法,而单独控制是否应该进行插值。
因此,假设,PowerShell可以使用一个单独的sigil进行字符串插值,比如$"..."
和$'...'
(类似于C#现在提供的内容,尽管它显然只有一个字符串引用样式)。(顺便说一句:Bash和Ksh有这种语法形式,但它有不同的用途(字符串的本地化),很少在实践中使用)。
然而,在实践中,一旦您了解了"..."
和'...'
在PowerShell中的工作方式,就不难使它们按预期工作。
有关PowerShell、cmd.exe
和POSIX兼容shell的基本功能,请参阅此答案。