2

I have a file structure like this:

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

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

      |- run_all.bat

index.js are files to be run be NodeJS with the node command. Both index.js files require a key that is stored in token.txt file. The index.js file reads the text file

activate.bat is simply this:

@echo off
node index.js

However I want to run both at once, and by only starting one .bat file, this is where run_all.bat comes in.

I have tried to run each file like I ran in activate.bat so:

@echo off

echo Starting all bots...

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

However I get an error:

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.

When run each activate.bat alone I do not get this error, what is going wrong? Are my batch commands somehow mixing up the different token.txt files

1
  • I really think this should be left as an answer, it is so complete, I can't test it right now. @Mofi Commented Dec 16, 2018 at 14:48

1 Answer 1

3

The main problem can be solved by using option /D of command START to define the current directory for the started processes. All index.js expect obviously that the file token.txt is in current directory and that the current directory is the directory containing both files. Windows sets the current directory by default to directory of the batch file on double clicking for example on batch file activate.bat.

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

The first double quoted argument string is interpreted by command START as optional title for the console window. node is started here without opening a console window. It is good practice to define always a title on using command START. In this case an empty window title specified with "" is a good choice as also on starting a Windows GUI application because no console window is opened at all.

The subdirectories test1 and test2 are always in directory containing the batch file run_all.bat. For that reason %~dp0 is used to reference the drive and path of argument 0 which is the currently executed batch file. This makes the batch file run_all.bat itself independent on what is the current directory on executing run_all.bat.

/ (forward slash) is the directory separator on Linux/Mac. But \ (backslash) should be used on Windows in file/folder paths because of / is used for options on Windows, except for applications ported from Unix to Windows without adaptation to Windows syntax. The Windows kernel functions for file/folder accesses replace all / by \ to automatically correct paths before accessing Windows file systems for compatibility reasons, but it is definitely better to write file/folder paths in Windows scripts with current directory separator and do not depend on this automatic correction of Windows kernel.

%~dp0 expands to a path string always ending with a backslash. So no additional backslash should be used on concatenating this dynamic string with a fixed file/folder name/path. Otherwise there would be two \ in series on execution. The Windows kernel functions for file/folder accesses automatically correct also \\ in a file/folder referencing string by \. But it is again better to avoid this mistake.

See the Microsoft documentation page Naming Files, Paths, and Namespaces for more details.

So command START sets now the directory containing index.js and token.txt before running node with the argument index.js.

A better solution would be using this batch file:

@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

The command FOR runs in a separate command process with cmd.exe /C (more precisely %CompSpec% /C in background the command line:

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

DIR outputs to handle STDOUT of started command process

  • in bare format because of option /B
  • the file names with extension and with full path because of option /S
  • of all only non-hidden files because of option /A-D-H (attribute not directory and not hidden)
  • with file name index.js found in specified directory or any subdirectory because of option /S.

The error message output by DIR to handle STDERR on not finding anything matching these criteria is suppressed by redirecting to device NUL.

Read the Microsoft documentation about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.

FOR with option /F captures the output to handle STDOUT of started background command process and processes this output after started cmd.exe terminated. Empty lines are always ignored by FOR which do not occur here. Lines starting with ; are by default also ignored by FOR because of the semicolon is the default end of line option. It is impossible that a full qualified file name as output by DIR starts with a semicolon and therefore default eol=; can be kept in this case. FOR would split up by default every line into substrings using normal space and horizontal tab as string delimiters and would assign just first space/tab delimited string to specified loop variable. This behavior is not wanted here because of file path could contain also one or more spaces. Therefore line splitting behavior is disabled with delims= which defines an empty list of delimiters resulting in always getting entire full qualified file name assigned to loop variable.

FOR executes for every file name output by DIR the command START as explained above. It does not matter for START if the directory path specified with /D"..." is without or with a backslash at end.

The main advantage of this second batch file solution in comparison to first one can be seen easily: run_all.bat must not be edited on removing or adding additional directories with index.js.

But be aware that running too many node instances parallel can be counterproductive depending on what code in index.js does. So it could be useful to extend the batch file to start not more than x node and halt batch file execution until one node instance terminated itself before starting next instance on reaching useful maximum number of parallel running node instances.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

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

PS: I suggest to specify node at least with file extension and best with full path to make the batch file independent on the environment variables PATHEXT and PATH.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.