在 Windows 命令提示符中使用 shebang/hashbang

39

我目前正在使用 serve 脚本在 Windows 7 上通过 Node.js 来提供目录服务。它在 MSYS shell 或使用 sh 中运行良好,因为我将 node.exe 和 serve 脚本放在了 ~/bin 目录下(该目录已添加到 PATH 环境变量中),只需输入“serve”即可正常运行,这是因为它的 Shebang#!)指令告诉 shell 使用 node 运行。

然而,Windows 命令提示符似乎不支持没有 *.bat 或 *.exe 扩展名的普通文件,也不支持 shebang 指令。是否有注册表键或其他技巧可以强制使内置的 cmd.exe 支持这种行为呢?

我知道我可以编写一个简单的批处理文件来使用 node 运行它,但我想知道是否可以以内置方式完成这项任务,这样我就不必针对每个类似此脚本编写脚本了。

更新:实际上,我在想,能否编写一个默认处理程序来处理所有“文件未找到”等情况,以便自动尝试在 sh -c 中执行它呢?

谢谢。


你考虑过回来更新被接受的答案吗?你所接受的那个是不正确的,而你下面有一个非常好的替代方案。 - Ben Collins
6个回答

55

是的,可以使用PATHEXT环境变量实现这一点。该变量也用于注册.vbs.wsh脚本以便直接运行。

首先,您需要扩展PATHEXT变量,以包含该服务脚本的扩展名(以下假设该扩展名为.foo,因为我不知道Node.js的扩展名)。

默认值类似于以下内容:

PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC

你需要更改它(通过控制面板)使其看起来像这样:

PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.FOO

使用控制面板 (控制面板 -> 系统 -> 高级系统设置 -> 环境变量) 可以将 PATHEXT 变量的值持久化。

然后你需要使用命令 FTYPEASSOC 来注册正确的带有该扩展名的“解释器”:

ASSOC .foo=FooScript
FTYPE FooScript=foorunner.exe %1 %*

(上面的示例不要脸地从ftype /?提供的帮助中获取。)

ASSOC和FTYPE将直接写入注册表,因此您需要具有管理员帐户才能运行它们。


11
这并不等同于shebang。Shebang适用于任何文件; 而这只适用于特定的文件扩展名。完全不同的概念。 - user541686
14
但它将允许用户立即运行文件,无需进一步操作。 - user330315
5
@Mehrdad,这基本上是“Windows版”的shebang。 - James
1
我从这篇文章中学到了很多。它让我想起了我写的一个批处理脚本,将.jar文件与java.exe关联起来:https://gist.github.com/djangofan/4144970 - djangofan
2
虽然这很完美地工作,但它让文件中的shebang行失去了意义——也许,在Windows下,最好完全忘记使用shebang,而是像上面描述的那样,完全使用自定义文件扩展名?!(至少这是我的教训) - petermeissner
显示剩余3条评论

4

命令提示符不支持shebang,但是有很多混合技术可用于将批处理和其他语言的语法组合在一个文件中。由于您的问题涉及node.js,因此这里提供了一个批处理-node.js混合体(将其保存为.bat.cmd扩展名):

0</* :{
        @echo off
        node %~f0 %*
        exit /b %errorlevel%
:} */0;


console.log(" ---Self called node.js script--- ");

console.log('Press any key to exit');
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.on('data', process.exit.bind(process, 0));

这项工作也可以使用其他语言完成,例如Ruby、Perl、Python、PHP等。


1
哇!这真的很好用。在我看来,这是最佳解决方案,因为它不需要对系统进行任何更改,并且适用于所有解释器。 - marlar
这是一个聪明的技巧。你有其他语言的参考/链接吗?特别是,我一直在尝试获取Python的等效代码,但我无法避免cmd在重新启动Python解释器之前打印一行代码(到目前为止,我最接近的是:rem="""\n@python.exe %~f0 %* & @exit /b %errorlevel%\n"""; del rem\n Cmd会打印第一行:rem="")。 - sdenham
1
@sdenham - 请查看此链接 -> https://dev59.com/bZ7ha4cB1Zd3GeqPfTD5#41642050 - npocmaka
1
谢谢!你救了我,让我不再被这个问题困扰,因为我已经没有太多时间可以浪费了。 - sdenham
关联解决方法(assoc,ftype)在shell环境中很好用,但在Windows API CreateProcess中也适用。 - bvanlew
你可以看到注释符号。 - Joao-3

1
这是一种简单的方法,可以强制Windows支持shebang,但文件命名有一个注意事项。将以下文本复制到批处理文件中,并按照REM注释中的一般思路操作。
@echo off

REM This batch file adds a cheesy shebang support for windows
REM Caveat is that you must use a specific extension for your script files and associate that extension in Windows with this batch program.
REM Suggested extension is .wss (Windows Shebang Script)
REM One method to still easily determine script type visually is to use double extensions.  e.g.  script.pl.wss

setlocal enableextensions disabledelayedexpansion
if [%1] == [] goto usage

for /f "usebackq delims=" %%a IN (%1) do (
  set shebang=%%a
  goto decode_shebang
)

:decode_shebang
set parser=%shebang:~2%
if NOT "#!%parser%" == "%shebang%" goto not_shebang

:execute_script
"%parser%" %*
set exit_stat=%errorlevel%
echo script return status: %exit_stat%
goto finale

:not_shebang
echo ERROR script first line %shebang% is not a valid shebang
echo       maybe %1 is not a shebanged script
goto finale

:usage
echo usage: %0 'script with #! shebang' [scripts args]+
echo        This batch file will inspect the shebang and extract the
echo        script parser/interpreter which it will call to run the script

:finale
pause
exit /B %exit_stat%

0

@npocmaka 感谢您的提示!经过一些尝试和错误,我发现批处理/PHP混合的等效方法如下:

<?/** :
@echo off
C:\tools\php81\php.exe -d short_open_tag=On %~f0 %*
exit /b
*/ ?>
<?php
header('Location: example.com/');
print("<body><h1>Hello PHP!<h1></body>");
?> 

0

不,没有办法“强制”命令提示符执行此操作。

Windows简单地不是像Unix/Linux那样设计的

有一个类似的外壳扩展吗?

我没有听说过,但应该在Super User上询问,而不是在这里。


2
可以的。请看我的回答。 - user330315

0

除非是实际的可执行二进制文件,否则无法执行随机文件。Windows CreateProcess() 函数并不设计用于此目的。它只能执行带有 MZ 魔数或扩展名在 %PATHEXT% 列表中的文件。

然而,CMD 本身通过 EXTPROC 子句对自定义解释器提供了有限的支持。限制是解释器也应支持并省略其执行中的此子句。


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