【问题标题】:Passing newline character to PowerShell via Cmd通过 Cmd 将换行符传递给 PowerShell
【发布时间】:2017-06-26 01:55:18
【问题描述】:

我正在尝试从 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"

脚本在 Windows Server 2012 R2 上运行,使用 PowerShell v4.0

【问题讨论】:

  • 顺便说一句:您可能指的是exit 0 而不是return 0 - 后者将输出文字0 而不是设置退出代码。
  • 我很困惑你的字符串 isn't 被插值,因为你没有使用 -File 并且默认值 - 直到 PSv5.1 - 是-Command。您是否真的在使用-File 而只是忘记在问题中包含它?例如,如果我在 v4 中运行 powershell.exe -NoProfile Write-Output "TEST`r`nTEST",我会得到 2 行。
  • @mklement0 有趣的是,powershell.exe script.ps1 "TEST'r'nTEST" 可以正确打印,但 powershell.exe script.ps1 "TEST 'r'nTEST" 只打印第一个 TEST。在我的真实示例中,我没有使用-File,但我确实有空格。当您使用 -Write-Output 而不是脚本时,它会打印额外的换行符。

标签: powershell cmd powershell-4.0


【解决方案1】:

tl;dr

使用-Command 并将整个 PowerShell 命令作为单个字符串 传递;例如:

 C:\> powershell -NoProfile -Command "script.ps1 \"TEST`r`nTEST\""
 TEST
 TEST

注意内部" 实例如何转义为\",当从外部 调用PowerShell 时需要这样做(或者,为了完全稳健,请在 中使用"^""(原文如此) >Windows PowerShellPowerShell (Core) v6+ 中的 "")。

在您的 特定 情况下,
powershell -NoProfile -Command script.ps1 "TEST`r`nTEST" 也可以,但通常只有在字符串没有嵌入 空格 时才能按预期工作.
鉴于 -Command 是 PSv5.1 之前的默认值,您的命令(如当前发布的那样)应该按原样工作。


从 PowerShell v5.1 开始,参数从外部传递给 powershell.exe

  • 受 PowerShell 解释的影响,包括字符串插值,默认情况下以及当您使用 -Command 时(即,既不指定 @ 987654333@ 和 -Command 目前默认为 -Command)。

  • 如果您使用 -File 调用脚本,

    不受解释 - (在 cmd.exe 可能解释之后)PowerShell 将所有参数视为 文字字符串

    • 警告:这个行为是currently being discussed 相对于 v6,因为它至少在一种情况下存在明显问题:尝试传递 Boolean价值观。

可选阅读:为什么在使用-Command 时应该将整个 PowerShell 命令作为单个 参数传递:

当您将-Command多个 参数一起使用时,PowerShell 实质上在执行之前将它们组装成一个命令行。

任何"..."-引用单个参数都会在此过程中丢失,这可能会产生意想不到的结果;例如:

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"

换句话说:在封闭的" 被删除后,生成的标记被空格分解为多个参数,就像往常一样。

【讨论】:

    【解决方案2】:

    该参数需要重新解释为 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
    

    【讨论】:

    • 感谢您的回复。我个人更喜欢传入 \r\n,然后在 PowerShell 中使用 'r'n 进行替换。我更好奇为什么从 cmd 调用时会发生这种情况。例如,如果你传入 'r'n,然后将 'r'n 替换为 'r'n,'r'n 仍然按字面意思输出,如果你将 'r'n 附加到 PowerShell 中的字符串,附加的'r'n 将输出作为换行符(但现有的仍然按字面意思输出)。我只是无法理解其背后的逻辑。
    • 关于不转义转义字符串的好消息。我想它确实回答了这个问题。我只是希望它从 cmd 执行此操作有一个更哲学的原因。
    • 对不起,我不能让它更富有哲理。我很高兴你能理解。很难向不了解转义字符的人解释。
    • 对这个脚本要非常小心——这使得将变量传递给脚本的人能够执行任意代码。
    • 因此首选替换选项
    【解决方案3】:

    回车和换行是值13和10的字节,不能写,看不到。

    为方便起见,在编写 PowerShell 代码时,该语言将允许您编写:

    "`r`n"
    

    在双引号字符串中,并且在处理 PowerShell 源代码时(并且在其他任何时候),它将读取这些并将它们替换为字节值 13 和 10。

    它是 PowerShell 标记器中的 this line of code

    对于 cmd.exe 解释器来说,反引号并没有什么特别之处,将它放在一个字符串中也没有什么特别之处——你可以把它放在一个带引号的字符串中

    '`n'
    

    或在字符串中替换它 - 除非您必须注意替换发生的时间。例如在您的评论中:

    例如,如果你传入'r'n,然后将'r'n替换为'r'n,'r'n仍然是字面输出

    因为你的代码

    -replace "`r`n"
    

    变成

    -replace "[char]13[char]10"
    

    你从外部传入的字符串包含

    `r`n
    

    它们不匹配。字符串中的 Backtick-n 并不神奇,PowerShell 引擎不会将字符串全部解释为 PowerShell 代码,参数或任何东西也不是。只有在这种情况下 - 当您编写 -replace 代码时,就会发生 实际换行符的交换。

    【讨论】:

      猜你喜欢
      • 2021-11-27
      • 2022-01-05
      • 2019-07-20
      • 2013-05-01
      • 2012-11-07
      • 2020-11-26
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      相关资源
      最近更新 更多