如何解决如何使 ($Line_1`n$Line_2) 在 CMD 脚本中工作?
我在 CMD 脚本文件中使用以下代码
PowerShell Add-Type -AssemblyName System.Windows.Forms;^
$Line_1 = 'Hello!';^
$Line_2 = 'How are you?';^
[System.Windows.Forms.MessageBox]::Show($Line_1)
以上只会显示($Line_1)
如果使用 ($Line_1`n$Line_2)
,则不会显示任何内容。
如何让它同时显示$Line_1
和$Line_2
?
解决方法
最简单的解决方案是(注意 \"$Line_1`n$Line_2\"
部分):
PowerShell -c Add-Type -AssemblyName System.Windows.Forms; ^
$Line_1 = 'Hello!'; ^
$Line_2 = 'How are you?'; ^
[System.Windows.Forms.MessageBox]::Show(\"$Line_1`n$Line_2\")
请注意,我已明确添加了 -c
(-Command
) 参数名称以表示正在传递 PowerShell 命令字符串。虽然这在 Windows PowerShell 中不是必需的,默认为 -Command
,但在 PowerShell (Core) 7+ 中,-File
是现在是默认设置 - 请参阅 Windows PowerShell 和 PowerShell (Core) 7+ 的 CLI 文档。
也就是说,您必须在 $Line_1`n$Line_2
中使用 "..."
,一个 expandable string,并且您必须\
-转义 { {1}} 个字符,以便 PowerShell 不会将它们作为其命令行解析的一部分剥离(在没有整体双引号的情况下,"
也可以使用) .
不幸的是,解析规则在使用 for /f
时改变,以便逐行处理 PowerShell 的输出和/或将其捕获到变量中:
注意:下面使用 """
来生成控制台输出,只是为了使用与 [Console]::WriteLine()
方法调用类似的语法,同时允许 {{1} 捕获某些内容}}。在现实生活中,没有很好的理由调用 [System.Windows.Forms.MessageBox]::Show()
。
for /f
-
[Console]::WriteLine()
必须另外被转义(在for /f "delims=" %%l in (' PowerShell -c Add-Type -AssemblyName System.Windows.Forms^; ^ $Line_1 ^= 'Hello!'^; ^ $Line_2 ^= 'How are you?'^; ^ [Console]::WriteLine^(\"$Line_1`n$Line_2\"^) ') do echo [%%l]
所看到的=,; ( )
字符串之外)。 -
如果您另外在
cmd.exe
中包含一个"..."
字符串以防止空格规范化(请参阅下一节)和该字符串则需要\"...\"
-转义嵌入的"..."
元字符,您必须莫名其妙地在 initial^
前面加上cmd.exe
;例如,"
换行符(位于命令内部行末尾的
^
)实际上在^"\"Marley ^& Me\""
中是可选的,但为了一致性而将它们包含在内。 >
引用和转义要求摘要:
-
带有续行的多行技术(行尾的
^
) - 在语法上不能使用for /f
引用整个 命令,因为^
不支持双引号多行 strings - 需要小心的"..."
-转义所有cmd.exe
元字符,应该传递给PowerShell,特别是^
,此外,如果从cmd.exe
语句中调用PowerShell,& | < > ^
- 除非这些字符碰巧是for /f
视为 double 引用的子字符串的一部分;例如,放置在,; = ( )
字符串内的cmd.exe
- 例如&
- 必须不能被\"...\"
-escaped(但见下文关于空白规范化)。-
作为一个例外,元字符
\"$Line_1`n & $Line_2\"
必须始终转义为^
(仅适用于批处理文件,不适用于命令提示符 - 请参阅{{ 3}}). -
此外,如果
%
有效(或%%
以setlocal enabledelayedexpansion
开头),cmd.exe
也必须转义,但如下所示:- 作为
/V:ON
(sic) outside!
所看到的^^!
字符串(其中另一个元字符只需要 一个cmd.exe
) - 作为
"..."
inside 这样的字符串(其他元字符需要没有转义)。
- 作为
当通过
^
调用时,续行是可选 - 也就是说,您可以省略命令内部行末尾的^!
。
-
-
每个语句都必须以
for /f
结尾(正如您所做的那样),因为换行符 (^
) 导致输入之间没有 换行符行,因此 PowerShell 将它们视为一行,多个语句必须以;
分隔。 -
因为
^
和 PowerShell 的 initial 命令行解析都不知道单引号字符串 (;
) 并且因为 转义cmd.exe
字符串中的'...'
字符在命令行解析过程中没有 语法 功能,如果这些字符串包含空格,则会被分解为 多个 参数:-
实际上,这些字符串中多个相邻空格的运行被标准化为每个单个空格。例如,
"
和\"...\"
最终被 PowerShell 视为'How are you?'
和\"How are you?\"
。 -
为避免这种情况,另外将这些字符串括在未转义
'How are you?'
中(如果 em>整个命令包含在"How are you?"
) 中:"
和"..."
。 -
PowerShell 最终应将其视为
"'How are you?'"
(插值)字符串,但棘手的部分是"\"How are you?\""
无法识别"..."
-转义cmd.exe
字符,因此 it 将\
视为双引号字符串 ("
),后跟一个不带引号的字符串 ("\"How are you?\""
),后跟另一个双引号字符串 ("\"
)。因此,此类字符串中的任何How are you?\
元字符都必须再次进行""
转义才能传递到 PowerShell(这不适用于包装的cmd.exe
字符串,例如^
);例如:'...'
- 在 PowerShell (Core) 7+ only 中,您可以通过使用
"'How are you?'"
而不是"\"rock ^& roll"\"
来避免这种额外的^
-escaping转义的 PowerShell""
(在 Windows PowerShell 上会再次导致空白规范化),与封闭的未转义\"
结合有效地导致 三重双引号:"
- 在 PowerShell (Core) 7+ only 中,您可以通过使用
-
PowerShell 如何解析传递给其 CLI 的 "..."
/ """How are you?"""
参数的参数:
PowerShell 为您提供传递命令字符串之间的选择
-
either:作为单个参数,包含在整体
-Command
中;例如:-c
-
或:多个 参数 - 可能单独使用
"..."
引用 - 然后 PowerShell 将这些参数连接起来形成一个字符串;例如:powershell -c "Get-Date -Format 'yyyy MMM'"
在这两种情况下,未转义 "..."
个字符都从参数中剥离,因为为了命令行 而不是生成的 PowerShell 命令。
剥离语法 powershell -c Get-Date -Format "'yyyy MMM'"
字符并用空格连接结果参数后(如果适用),Powershell 将结果字符串解释为 PowerShell 代码。
注意:这与您使用 "
CLI 参数调用 脚本文件 并将参数传递给它时解析参数的方式有根本的不同 - 有关更多信息,请参阅 this answer .
显然 $Line_1 + "`n" + $Line_2
和 "$Line_1`n$Line_2"
工作正常。将命令字符串从 cmd 发送到 PowerShell 非常棘手,因为它具有传统的怪癖:
- 在 cmd
()
中,不同地方的特殊字符表示一个块 - 令牌分隔符不仅是
<space>
和<tab>
,还有;
,
=
<0x0B>
<0x0C>
and<0xFF>
。这会更改 cmd 的标记化行为,但被调用的命令可能会再次使用其规则重新解析命令
根据文档,PowerShell 期望最后一个参数中的单个字符串中的命令(这并不完全正确,因为文档没有正确更新),所以你需要引用整个内容或转义所有的分隔符。最简单的解决方案是使用单行并像这样转义 "`n"
中的引号
PowerShell "Add-Type -AssemblyName System.Windows.Forms; $Line_1 = 'Hello!'; $Line_2 = 'How are you?'; [System.Windows.Forms.MessageBox]::Show($Line_1 + \"`n\" + $Line_2)"
如果您想将命令放在多行中,则不能引用字符串。要将整个内容作为单个参数,现在您需要转义所有空格(在这种情况下您不需要转义 ;
,可能是因为在将命令行传递给 PowerShell 后,它会调用 {{ 1}} 并再次解析整个事情本身)
GetCommandLineW
或者,您可以通过直接使用 PowerShell Add-Type^ -AssemblyName^ System.Windows.Forms;^
$Line_1^ =^ 'Hello!';^
$Line_2^ =^ 'How^ are^ you?';^
[Windows.Forms.MessageBox]::Show($Line_1^ +^ \"`n\"^ +^ $Line_2)"
获取新行来避免使用 "`n"
字符串
[char]10
最后一个无需任何转义即可工作的解决方案,它利用 PowerShell 的 PowerShell -Command Add-Type -AssemblyName System.Windows.Forms;^
$Line_1 = 'Hello!';^
$Line_2 = 'How are you?';^
[System.Windows.Forms.MessageBox]::Show($Line_1 + [char]10 + $Line_2)
选项接收 UTF-16 命令字符串的 base64 编码字符串。您可以通过在 PowerShell 中运行它来获取编码版本
EncodedCommand
获得编码版本后,您可以从 cmd 调用它
$str = @'
>> Add-Type -AssemblyName System.Windows.Forms;
>> $Line_1 = 'Hello!';
>> $Line_2 = 'How are you?';
>> [System.Windows.Forms.MessageBox]::Show($Line_1 + "`n" + $Line_2)
>> '@
PS C:\Users\phucl> [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($str))
QQBkAGQALQBUAHkAcABlACAALQBBAHMAcwBlAG0AYgBsAHkATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVwBpAG4AZABvAHcAcwAuAEYAbwByAG0AcwA7AAoAIAA9ACAAJwBIAGUAbABsAG8AIQAnADsACgAgAD0AIAAnAEgAbwB3ACAAYQByAGUAIAB5AG8AdQA/ACcAOwAKAFsAUwB5AHMAdABlAG0ALgBXAGkAbgBkAG8AdwBzAC4ARgBvAHIAbQBzAC4ATQBlAHMAcwBhAGcAZQBCAG8AeABdADoAOgBTAGgAbwB3ACgAIAArACAAIgAKACIAIAArACAAKQA=
,
有多种连接字符串的方法可以查找,但最简单的方法可能是使用 + 符号。 `n 是一个换行符,它将第 2 行置于第 1 行下方。请注意,` 是一个反引号(通常与波浪号 ~ 位于同一键上)
[System.Windows.Forms.MessageBox]::Show($Line_1 + "`n" + $Line_2)
再次查看您的帖子后,我注意到您与 ($Line_1`n$Line_2) 很接近。你只是缺少一些双引号
[System.Windows.Forms.MessageBox]::Show("$Line_1`n$Line_2")
的更多信息版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。