从批处理脚本中执行WshShell命令

4

我有一个简单的问题:

如何在Windows批处理(.bat)脚本中执行单个WshShell命令的最佳方法?

(希望不是通过VB代码创建一个新文件)

4个回答

8
您可以通过VBScript或Jscript访问WshShell。两者都可以嵌入批处理文件中,但是JScript更加简洁。
大多数人通过编写临时的VBS文件来在批处理中执行VBScript。但是也有可能不需要临时文件就能完成操作。请参见Is it possible to embed and execute VBScript within a batch file without using a temporary file?以了解各种选项。
将JScript嵌入批处理非常容易。请参见https://dev59.com/CE3Sa4cB1Zd3GeqPrgeX#5656250。我使用该技术的一个非常微小的变体。
@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment

:: ******* Begin batch code *********
@echo off
:: Your batch logic goes here

:: At any point you can execute the following to access your JScript
cscript //E:JScript //nologo "%~f0" yourJscriptParametersGoHere

:: Be sure to terminate your script so that 
:: it does not fall through into the JScript code
exit /b

********* Begin JScript code **********/
var WshShell=WScript.CreateObject("WScript.Shell")

/* do whatever with your WshShell object */

解释:

这种技术的关键是第一行,它必须是既符合JScript又符合批处理语法的有效行。

批处理将第一行视为一个简单的IF命令,该命令始终评估为false,因此它永远不会执行不存在的@end命令,也不会造成任何损害。接下来的几行都是普通的批处理代码,直到达到exit /b,批处理过程终止,剩余的行被忽略。

JScript将第一行视为一个空的条件编译块,后跟一个多行注释的开头。由于这些代码都是注释的一部分,因此JScript会忽略以下的批处理代码。注释以*/结束,然后是正常的JScript代码。

唯一可能失败的事情是,如果您的批处理代码必须包含*/,因为这会提前终止JScript注释。但可以通过在*/之间放置某些内容来解决这个问题,在批处理解析后消失即可。如果代码没有引号,则可以使用以下方式转义斜杠:*^/。如果代码带引号,则可以展开一个未定义的变量:*%=%/。保证未定义一个名为=的变量。


虽然我不会经常使用这种方法,但是你的脚本是如何工作的? - BDM

7
这是我用来编写批处理-JScript混合脚本的方法:
@if (@CodeSection == @Batch) @then

:: The first line above is...
:: in Batch: a valid IF command that does nothing.
:: in JScript: a conditional compilation IF statement that is false,
::             so this section is omitted until next "at-sign end".


@echo off

rem EXPR.BAT: Evaluate a JScript (arithmetic) expression
rem Antonio Perez Ayala

rem Define an auxiliary variable to call JScript
set JSCall=Cscript //nologo //E:JScript "%~F0"

rem Do Batch business here, for example:
%JSCall% %1
goto :EOF

End of Batch section


@end


// JScript section

WScript.Echo(eval(WScript.Arguments.Unnamed.Item(0)));

例如:

EXPR 1/3

编辑:如果您想要更简单/更短的方法,请使用以下方法:
@set @a=0  /*
@cscript //nologo //E:JScript "%~F0" "%~1"
@goto :EOF */

WScript.Echo(eval(WScript.Arguments(0)));

首先,@set @a=0 /* 是JScript和Batch中都有效的语句/命令,它只用于插入JScript注释的开头(/*),以便JScript忽略Batch部分。最终的goto :EOF之后,注释被关闭(*/)。

编辑:一种更简单的方法...

@set @a=0 // & cscript //nologo //E:JScript "%~F0" "%~1" & goto :EOF

WScript.Echo(eval(WScript.Arguments(0)));

啊,这就是我在你回答我的问题时寻找的解释。我将编辑您的回复并复制注释行。 - T.Rob

2

感谢以上内容的启发,让我做了一些微小的修改。

@if (false)==nul ======= CMD code =======
@echo off
::code before Cscript
cscript //nologo //e:jscript "%~f0" %*
echo it returns: %errorlevel%
::code after Cscript 
exit /b
=================================
Freedom Land ^o^
======= J/VB Script code ======
@end
// Start Cscript
WScript.Echo("wsh says: Hello, Universe!");
WScript.Quit(123.456)

0

你也可以使用适用于 Node.js 的这种方法:

0</* ::

@echo off

    echo hello from batch

    rem -- CALLING NODE
    ::node "%~f0" %*

    rem -- CALLING CSCRIPT
    cscript //E:JScript //nologo "%~f0" %*

exit /b %errorlevel%


*/0;

// -- NODE CODE
//console.log('Hello from Node');

// -- JScript CODE 
WScript.Echo("Hello from JSCript")

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