【问题标题】:Running multiple NodeJS projects at once with a batch file使用批处理文件一次运行多个 NodeJS 项目
【发布时间】:2019-05-17 01:56:43
【问题描述】:

我有这样的文件结构:

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 文件

【问题讨论】:

  • 我真的觉得这个应该留作答案,太完整了,我现在没法测试。 @Mofi

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


【解决方案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.jstoken.txt 的目录,然后运行node 并使用参数index.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(属性不是目录且未隐藏),所有仅非隐藏文件中
  • 由于选项/S,在指定目录或任何子目录中找到文件名index.js

通过重定向到设备 NUL 来抑制 DIR 输出的错误消息以处理 STDERR 未找到任何符合这些条件的内容。。 p>

阅读有关Using Command Redirection Operators 的Microsoft 文档以了解2&gt;nul 的解释。重定向运算符 &gt; 必须在 FOR 命令行上使用插入字符 ^ 转义,以便在 Windows 命令解释器在执行命令 FOR 之前处理此命令行时解释为文字字符> 在后台启动的单独命令进程中执行嵌入的dir 命令行。

带有选项/F

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

FORDIR 命令 START 输出的每个文件名执行如上所述。用/D"..." 指定的目录路径是否在末尾没有或带有反斜杠对于START 无关紧要。

与第一个批处理文件解决方案相比,第二个批处理文件解决方案的主要优势显而易见:run_all.bat 不得在使用index.js 删除或添加其他目录时进行编辑。

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

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

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

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

【讨论】:

    猜你喜欢
    • 2022-07-22
    • 1970-01-01
    • 2013-01-11
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    • 2017-08-14
    • 1970-01-01
    相关资源
    最近更新 更多