通过Cmd将换行符传递给PowerShell

时间:2017-06-26 01:55:18

标签: powershell cmd powershell-v4.0

我尝试从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上运行

3 个答案:

答案 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的参数:

    PowerShell
  • 需要解释,包括字符串插值,默认情况下 以及使用-Command 时(即,既不指定-File也不指定-Command当前默认为-Command)。

  • 如果您使用 -File 来调用脚本,则
  • 不受解释 - (在cmd.exe的潜在解释之后)PowerShell将所有参数视为 文字字符串

    • 警告:对于v6 ,此行为为currently being discussed,因为至少在一种情况下它是明显有问题的:尝试传递布尔值。

可选阅读:使用-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"

换句话说:在删除封闭的"后,生成的令牌会像往常一样被空格分成多个参数。