我尝试从Windows cmd.exe运行PowerShell脚本。 PowerShell脚本的输入是一个字符串,其中包含使用PowerShell反引号转义的换行符 - 即:
`r`n
出于演示目的,输入字符串然后被写入控制台,并且也被转储到文件中。
我遇到的问题是当使用语法
从cmd.exe运行脚本时powershell.exe script.ps1 "TEST`r`nTEST"
字符串中的换行符不被视为换行符,并且在控制台输出和输出文本文件中都包含在字面上。
TEST`r`nTEST
但是,如果我从PowerShell环境运行它,我会得到预期的结果(即正确解析换行符,并在适当的位置插入换行符。)
TEST
TEST
同样,如果我通过Windows cmd.exe传入\r\n
而不是转义的换行符,并在PowerShell脚本中执行.replace
$date = $data.replace("\r\n","`r`n")
我得到了预期的输出:
TEST
TEST
是否有人能够阐明为何会发生这种情况?
测试脚本如下:
param([string]$data) # data to send
Write-Host $data
[IO.File]::WriteAllText('d:\temp.txt', $data)
return 0
从命令行调用该文件:
powershell.exe script.ps1 "TEST`r`nTEST"
该脚本使用PowerShell v4.0在Windows Server 2012 R2上运行
答案 0 :(得分:1)
该参数需要重新解释为PowerShell字符串。这会让你走上正轨吗?
-replace
无效的原因是原始字符串实际上包含反引号。它需要在搜索字符串中进行转义。
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
答案 1 :(得分:1)
回车符和换行符是值为13和10的字节,你不能写它们,你看不到它们。
为方便起见,在编写PowerShell代码时,该语言将允许您编写:
--inspect
在双引号字符串中,当处理PowerShell源代码时(并且在其他时间),它将读取它们并用字节值13和10替换它们。
PowerShell tokenizer中的this line of code可以执行此操作。
cmd.exe解释器的backtick-n没有什么特别之处,没有什么特别的可以将它放在一个字符串中 - 你可以把它放在一个带引号的字符串中
"`r`n"
或用字符串替换它 - 除了你必须注意更换发生时。例如在你的评论中:
例如,如果你传入'r'n然后用'r'n替换'r'n,'r'n仍然按字面输出
因为你的代码
'`n'
成为
-replace "`r`n"
并且从外部传入的字符串包含
-replace "[char]13[char]10"
他们不匹配。字符串中的Backtick-n不是魔术,PowerShell引擎不会将字符串全部解释为PowerShell代码,也不是参数或任何东西。而且只有在这种情况下 - 当你编写你的替换代码时,就会发生实际换行符的交换。
答案 2 :(得分:1)
<强> TL;博士强>
使用-Command
并将整个 PowerShell命令作为单字符串传递; e.g:
C:\> powershell -NoProfile -Command "script.ps1 \"TEST`r`nTEST\""
TEST
TEST
请注意内部"
实例如何作为\"
进行转义,PowerShell在从外部调用时需要这样做(或者,使用"""
)。
在特定案例中,
powershell -NoProfile -Command script.ps1 "TEST`r`nTEST"
也会起作用,但通常只有在字符串没有嵌入空格时才能按预期工作。
鉴于-Command
是默认直到PSv5.1,您的命令 - 如当前发布的 - 应该 as-is 。
从PowerShell v5.1开始,从外部传递给powershell.exe
的参数:
需要解释,包括字符串插值,默认情况下 以及使用-Command
时(即,既不指定-File
也不指定-Command
当前默认为-Command
)。
-File
将是默认行为 - 请参阅relevant change on GitHub。-File
来调用脚本,则 不受解释 - (在cmd.exe
的潜在解释之后)PowerShell将所有参数视为 文字字符串 。
-Command
时,为什么要将整个 PowerShell命令作为单参数传递:当您将-Command
与多个参数一起使用时,PowerShell实际上会在执行它们之前将它们组装成一个命令行。
任何"..."
- 引用个别参数都会在此过程中丢失,这可能会产生意外结果; e.g:
C:\> powershell -NoProfile -Command "& { $args.count }" "line 1`r`nline 2"
3 # !! "line 1`r`nline 2" was broken into 3 arguments
鉴于在解析命令行的过程中删除了外部"..."
引用,PowerShell最终执行的实际命令行是:
C:\ PS> & { $args.Count } line 1`r`nline 2
3
为了说明原因,让我们看一下使用显式引用的等效命令:
C:\ PS> & { $args.Count } "line" "1`r`nline" "2"
换句话说:在删除封闭的"
后,生成的令牌会像往常一样被空格分成多个参数。