Passing newline character to PowerShell via Cmd
我正在尝试从Windows cmd.exe运行PowerShell脚本。 PowerShell脚本的输入是一个字符串,其中包含使用PowerShell反引号转义的换行符-即:
1 | `r`n |
出于演示目的,然后将输入字符串写入控制台,并转储到文件中。
我的问题是,使用语法从cmd.exe运行脚本时
1 | powershell.exe script.ps1"TEST`r`nTEST" |
字符串中的换行符不会被视为换行符,并且实际上包含在控制台输出和输出文本文件中。
1 | TEST`r`nTEST |
但是,如果我在PowerShell环境中运行此程序,则会得到预期的结果(即正确解析了换行符,并在适当的位置插入了换行符)。
1 2 | TEST TEST |
同样,如果我通过Windows cmd.exe传递
\
1 2 3 | $date = $data.replace("\ \ ","`r`n") |
我得到了预期的输出:
1 2 | TEST TEST |
有谁能够阐明为什么会发生这种情况?
测试脚本如下:
1 2 3 4 5 | param([string]$data) # data to send Write-Host $data [IO.File]::WriteAllText('d:\\temp.txt', $data) return 0 |
该文件从命令行调用为:
1 | powershell.exe script.ps1"TEST`r`nTEST" |
该脚本使用PowerShell v4.0在Windows Server 2012 R2上运行
tl; dr
使用
1 2 3 | C:\\> powershell -NoProfile -Command"script.ps1 \"TEST`r`nTEST\"" TEST TEST |
请注意,内部
在您的特定情况下,
鉴于
从PowerShell v5.1开始,参数从外部传递给
-
默认情况下以及使用
-Command 时,PowerShell会对其进行解释,包括字符串插值(即,当前不指定-File 或-Command 都默认为-Command )。-
注意:默认行为将在v6中更改:
-File 将是默认行为,然后-在GitHub上查看相关更改。
-
注意:默认行为将在v6中更改:
-
如果使用
-File 调用脚本,则不需要进行解释-(在cmd.exe 可能解释之后)PowerShell将所有参数视为文字字符串。- 警告:目前正在针对v6讨论此行为,因为在至少一种情况下它存在明显的问题:尝试传递布尔值。
可选阅读:为什么在使用
当您将
各个参数周围的所有
1 2 | C:\\> powershell -NoProfile -Command"& { $args.count }""line 1`r`nline 2" 3 # !!"line 1`r`nline 2" was broken into 3 arguments |
假定在解析命令行的过程中删除了外部
1 2 |
为了说明原因,让我们看一下使用显式引用的等效命令:
1 |
换句话说:除去封闭的
回车符和换行符是具有值13和10的字节,您无法编写它们,也看不到它们。
为方便起见,在编写PowerShell代码时,该语言将允许您编写:
1 | "`r`n" |
用双引号引起来的字符串,并且在处理PowerShell源代码时(并且在其他时间),它将读取这些源代码并将其替换为字节值13和10。
正是PowerShell令牌生成器中的这一行代码可以实现。
cmd.exe解释器的backtick -n没什么特别的,把它放在字符串中也没什么特别的-您可以将它放在一个引号中
1 | '`n' |
或将其替换为字符串-除非必须注意替换发生的时间。例如在您的评论中:
For example, if you pass in 'r'n and then replace 'r'n with 'r'n, the 'r'n is still output literally
因为你的代码
1 | -replace"`r`n" |
变成
1 | -replace"[char]13[char]10" |
并且从外部传入的字符串包含
1 | `r`n |
他们不匹配。字符串中的反引号-n并不是魔术,PowerShell引擎不会将字符串全部解释为PowerShell代码,参数也不是。仅在这种情况下-编写-replace代码时,即发生实际换行符的交换。
该参数将需要重新解释为PowerShell字符串。这会帮助您前进吗?
您的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | C:\\src\\t>type p1.ps1 Param([string]$s) Write-Host $s $p = Invoke-Expression `"$s`" Write-Host $p $p2 = $s -replace"``r``n","`r`n" Write-Host $p2 C:\\src\\t>powershell -noprofile -file .\\p1.ps1"TEST`r`nTEST" TEST`r`nTEST TEST TEST TEST TEST |