Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange redirect in Batch/Powershell polyglot

While attempting to rewrite a batch file, I was looking into the possibility of using powershell. The main issue that I had with it was that .ps1 files aren't executable by default. I found a solution here, which I'll copy below, but I'm very confused about the syntax on the first line:

<# : 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...

Here's what I know from testing:

  • The space between <# and : is required, though there can be multiple.
  • It can also have a number 0-9 beforehand, such as 3<# :, which makes me suspect that there's some weirdness involving redirects and labels.
  • The text after the colon is ignored and not necessary
  • If I add a command before it, such as git <# : batch script, the shell shows that it tried to evaluate git : batch script 0<# and can't find the file specified
  • Changing the # to a valid filename makes the complaint go away (naturally)
  • Attempting to run the line in an interactive session actually causes it to complain about not being able to find the file specified, but running it from a script (even if it's the only line in the .cmd file) silently succeeds

That last bullet is the part I'm trying to figure out. What's different about the environments? My understanding was that part of the issue was that running a bat file is parsed as if each line were manually entered. Why doesn't it complain about # being an invalid file when called via a script?

like image 311
Matt Soucy Avatar asked May 10 '17 02:05

Matt Soucy


1 Answers

"...running a bat file is parsed as if each line were manually entered."

No, parser rules are sometimes different between command line and batch file and in this case the difference is critical.

It complains about # being an invalid file in command line, and not in batch file, because the <# : construct is (to the batch parser) just a redirected label. The same kind of label you use in goto :label or call :label.

That means that the redirection, that is not executed in batch file as the "command" associated to the redirection is a label, is executed in command line as you can not have a label in a command line.

like image 195
MC ND Avatar answered Oct 10 '22 08:10

MC ND