使用批处理文件一次运行多个NodeJS项目

时间:2018-12-16 13:39:17

标签: node.js batch-file batch-processing

我有这样的文件结构:

bots -|
      |- test1 -|
                |- index.js
                |- activate.bat
                |- token.txt

      |- test2 -|
                |- index.js
                |- actiate.js
                |- token.txt

      |- run_all.bat

index.js是要使用node命令由NodeJS运行的文件。这两个index.js文件都需要一个存储在token.txt文件中的密钥。 index.js文件读取文本文件

activate.bat就是这样:

@echo off
node index.js

但是我想一次运行两个,并且只启动一个.bat文件,这就是run_all.bat进入的地方。

我尝试运行每个文件,就像我在activate.bat中运行一样,

@echo off

echo Starting all bots...

start /b node test1\index.js
start /b node test2\index.js

但是我得到一个错误:

PS C:\Users\Simon\Desktop\bot> ./run_all.bat
Starting all bots...
PS C:\Users\Simon\Desktop\bot> test1 running
test2 running
(node:10176) UnhandledPromiseRejectionWarning: Error: An invalid token was provided.
    at Promise (C:\Users\Simon\node_modules\discord.js\src\client\rest\RESTMethods.js:34:54)
    at new Promise (<anonymous>)
    at RESTMethods.login (C:\Users\Simon\node_modules\discord.js\src\client\rest\RESTMethods.js:33:12)
    at Client.login (C:\Users\Simon\node_modules\discord.js\src\client\Client.js:279:30)
    at ReadFileContext.callback (C:\Users\Simon\Desktop\bot\test1\index1.1.js:88:12)
    at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:235:13)
(node:4836) UnhandledPromiseRejectionWarning: Error: An invalid token was provided.
    at Promise (C:\Users\Simon\node_modules\discord.js\src\client\rest\RESTMethods.js:34:54)
    at new Promise (<anonymous>)
    at RESTMethods.login (C:\Users\Simon\node_modules\discord.js\src\client\rest\RESTMethods.js:33:12)
    at Client.login (C:\Users\Simon\node_modules\discord.js\src\client\Client.js:279:30)
    at ReadFileContext.callback (C:\Users\Simon\Desktop\bot\test2\index.js:65:12)
    at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:235:13)
(node:10176) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 3)
(node:4836) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 3)
(node:10176) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:4836) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

单独运行每个activate.bat时,我出现此错误,这是怎么回事?我的批处理命令是否以某种方式混淆了不同的token.txt文件

1 个答案:

答案 0 :(得分:1)

主要问题可以通过使用命令 START 的选项/D来定义启动进程的当前目录来解决。所有index.js显然都希望文件token.txt在当前目录中,而当前目录是包含两个文件的目录。 Windows默认会在双击(例如在批处理文件activate.bat上)时将当前目录设置为批处理文件的目录。

@echo off
echo Starting all bots...
start "" /B /D"%~dp0test1" node index.js
start "" /B /D"%~dp0test2" node index.js

第一个双引号参数字符串由命令 START 解释为控制台窗口的可选标题。 node在这里启动,而无需打开控制台窗口。优良作法是始终使用命令 START 定义标题。在这种情况下,用""指定一个空的窗口标题是一个很好的选择,因为在启动Windows GUI应用程序时,因为根本没有打开控制台窗口。

子目录test1test2始终位于包含批处理文件run_all.bat的目录中。因此,%~dp0用于引用参数0的驱动器和路径,该参数是当前执行的批处理文件。这使批处理文件run_all.bat本身独立于执行run_all.bat时的当前目录。

/(正斜杠)是Linux / Mac上的目录分隔符。但是,\(反斜杠)应在Windows中的文件/文件夹路径中使用,因为/用于Windows上的选项,除了从Unix移植到Windows的应用程序(不适应Windows语法)。出于兼容性原因,用于文件/文件夹访问的Windows内核功能将所有/替换为\,以便在访问Windows文件系统之前自动更正路径,但是使用Windows脚本编写文件/文件夹路径绝对更好当前目录分隔符,并且不依赖于Windows内核的这种自动更正。

%~dp0扩展为始终以反斜杠结尾的路径字符串。因此,在将此动态字符串与固定的文件/文件夹名称/路径连接时,不应使用其他反斜杠。否则,将在执行时串联两个\。用于文件/文件夹访问的Windows内核功能还自动纠正\\在文件/文件夹引用字符串中的\。但是最好还是避免这个错误。

有关更多详细信息,请参见Microsoft关于Naming Files, Paths, and Namespaces的文章。

因此,命令 START 现在在使用参数index.js运行token.txt之前设置包含nodeindex.js的目录。

更好的解决方案是使用此批处理文件:

@echo off
echo Starting all bots...
for /F "delims=" %%I in ('dir "%~dp0index.js" /A-D-H /B /S 2^>nul') do start "" /B /D"%%~dpI" node index.js

FOR 命令在单独的命令进程中运行,cmd.exe /C(更确切地说,%CompSpec% /C在命令行的后台运行:

dir "C:\Users\Simon\Desktop\bot\index.js" /A-D-H /B /S 2>nul

DIR 输出以处理已启动命令过程的 STDOUT

  • 由于选项/B而以裸格式显示
  • 由于选项/S
  • 而具有扩展名的文件名以及完整路径
  • 由于选项/A-D-H而导致的所有仅非隐藏文件(属性不是目录,也不是隐藏的)
  • 由于选项index.js在指定目录或任何子目录中找到文件名/S

DIR 输出的错误消息,用于在找不到符合这些条件的任何内容时处理 STDERR ,该错误消息通过重定向到设备 NUL 得到抑制。

阅读有关Using Command Redirection Operators的Microsoft文章,以获取2>nul的解释。当Windows命令解释器在执行命令之前处理此命令行时,重定向操作符>必须在 FOR 命令行上使用脱字符号^进行转义,才能被解释为文字字符。 FOR ,它将在后台启动的单独命令进程中执行嵌入式dir命令行。

带有选项/F

FOR 捕获输出以处理启动的后台命令进程的 STDOUT ,并在启动cmd.exe终止后处理该输出。空行始终被 FOR 忽略,此处不会出现。默认情况下,以;开头的行也会被 FOR 忽略,因为分号是默认的行尾选项。 DIR 输出的完全合格文件名不可能以分号开头,因此在这种情况下可以保留默认的eol=; FOR 默认情况下会使用普通空格和水平制表符作为字符串定界符将每一行拆分为子字符串,并且仅将第一个空格/制表符分隔的字符串分配给指定的循环变量。这里不希望出现这种情况,因为文件路径可能还包含一个或多个空格。因此,delims=禁用了行拆分行为,该行定义了一个空的定界符列表,从而导致始终将完整的合格文件名分配给循环变量。

DIR 命令 START 输出的每个文件名执行

FOR ,如上所述。对于 START 而言,是否用/D"..."指定的目录路径没有末尾或反斜杠都没有关系。

与第一个批处理文件解决方案相比,第二个批处理文件解决方案的主要优点很容易看出:在使用run_all.bat删除或添加其他目录时,不得编辑index.js

但是请注意,并行运行太多node实例可能会适得其反,具体取决于index.js中的代码。因此,扩展批处理文件以使其启动不超过 x node并暂停批处理文件执行直到一个node实例终止自身,然后再启动下一个实例才有用可能会很有用。并行运行的node个实例的最大数量。

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • dir /?
  • echo /?
  • for /?
  • start /?

PS:我建议至少使用文件扩展名指定node,最好用完整路径指定PATHEXT,以使批处理文件独立于环境变量PATH和{{1}}。