Batch/Powershell多语言混合程序中的奇怪重定向

10

在尝试重写批处理文件时,我正在考虑使用powershell的可能性。我遇到的主要问题是默认情况下无法执行 .ps1 文件。我在这里找到了解决方案,我将复制以下内容,但我对第一行的语法非常困惑:

<# : batch script
@echo off
setlocal
cd %~dp0
powershell -executionpolicy remotesigned -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))"
endlocal
goto:eof
#>
# here write your powershell commands...

这是我从测试中了解到的:

  • <#: 之间需要空格,可以有多个。
  • 它也可以有数字 0-9 在前面,例如 3<# :,这让我怀疑可能涉及到重定向和标签的一些奇怪问题。
  • 冒号后面的文本将被忽略且不必要。
  • 如果我在其前面添加一个命令,例如 git <# : batch script,则 shell 显示它尝试评估 git : batch script 0<# 并找不到指定的文件。
  • # 更改为有效的文件名使投诉消失(自然而然)。
  • 尝试在交互式会话中运行该行实际上会导致它抱怨无法找到指定的文件,但是从脚本中运行它(即使它是 .cmd 文件中的唯一行)会在不发出任何声音的情况下成功执行。

我正在努力弄清楚的是最后一条。环境有何不同?我的理解是运行 bat 文件时,它被解析为手动输入每行。为什么通过脚本调用时它不会抱怨 # 是无效文件?


你确定这不是一个多行注释,用于展示“旧”的批处理代码吗? - Moerwald
2个回答

9

"...运行bat文件时,每一行都会被解析为手动输入的."

不,解析器规则在命令行和批处理文件之间有时是不同的,在这种情况下差异非常重要。

它抱怨在命令行中#是无效的文件,在批处理文件中却不是,因为对于批处理解析器来说,<# :结构只是一个重定向的标签,与你在goto :labelcall :label中使用的相同类型的标签。

这意味着重定向在批处理文件中不会执行,因为与重定向关联的“命令”是一个标签,在命令行中将执行重定向,因为你不能在命令行中有一个标签。


有没有文档显示这个?我仍然不完全确定为什么存在差异,因为似乎我可以在交互式会话中创建标签? - Matt Soucy
1
@MattSoucy,如果你在命令行中使用类似于:label的东西,你将不会有一个标签(你不能gotocall到它),但是只要第一个非空格/非分隔符字符是冒号,就会有一个空命令(我必须给它一个名字)。你可以使用:label <file(带有file存在或不存在)并且它会“工作”(空命令),但是如果你写<file :label(带有file存在),重定向会改变解析,并且你将得到一个错误,因为:label无法被处理为一个命令。你只能在批处理文件中使用标签 - MC ND

2
这个技巧需要同时考虑到PowerShell和批处理的语法规则。
对于PowerShell来说,只需使用<#标记就可以开启多行注释。
而对于批处理来说,你需要一个有效的代码结构,但无论echo on状态如何,这个结构都不会被显示。因此,在这种情况下,用冒号是非常完美的,因为标签行不会被显示出来。
当你将这个冒号替换为REM时,你可以看到解析器的输出结果。
<# REM Batch script

输出:

c:\Temp>REM batch script 0<#
< p > < code >#是一个有效的文件名,但文件本身从未被访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接