使用文件名掩码启动并发批处理,然后等待它们完成 [英] Start concurrent batches with filename mask and wait for them to finish

查看:102
本文介绍了使用文件名掩码启动并发批处理,然后等待它们完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试启动固定数量的并发批处理,这些并发批处理具有相似的文件名,并且都在同一目录中:

TestMe1.bat
TestMe2.bat
TestMe3.bat

所有批次应同时开始,并且所有批次都应在该批次继续之前完成,例如一个master.bat:

echo Starting batches

(
start "task1" cmd /C "TestMe1.bat"
start "task2" cmd /C "TestMe2.bat"
start "task3" cmd /C "TestMe3.bat"
) | pause

echo All batches have stopped and we can safely continue

我正在尝试找到一种方法来启动与TestMe * .bat匹配的目录中的所有批次,这样我就不必每次都制作一个新的master.bat文件.像这样的东西,但是,你知道,正在工作:

echo Starting batches

(
for /f "delims=" %%x in ('dir /b /a-d TestMe*.bat') do start "task" cmd /C "%%x"
) | pause

echo All batches have stopped and we can safely continue

感谢 使我走得更远.

我们深深地收到了建议和想法!

解决方案

首先,您必须了解这种使用pause命令使用管道的特殊方法是如何工作的,以及为什么可以将其用于等待多个并行进程./p>

以您的第一个工作代码示例作为起点

(
start "task1" cmd /C "TestMe1.bat"
start "task2" cmd /C "TestMe2.bat"
start "task3" cmd /C "TestMe3.bat"
) | pause

之所以起作用,是因为start命令调用的每个CMD新实例都将在新控制台中启动,并且其stdoutstderr重定向到该新控制台,因此子CMD的输出将不会被重定向到管道,因此不会被正在等待管道输入的pause命令使用.

按钮,

仍然每个进程都继承了管道句柄,因此只要子进程仍处于活动状态,管道的句柄将保持打开状态.

因此,管道右侧的pause命令将保持活动状态,等待管道左侧的输入,直到它接收到来自管道的输入(这将永远不会发生)或所有子进程都具有终止并关闭管道的手柄.

因此,正在执行母版批处理文件的主CMD实例实际上正在等待pause命令(管道的右侧)终止,而该命令又正在等待子进程(潜在的管道编写器)终止.

现在很清楚为什么您尝试的第二个涉及FOR循环的代码无法正常工作.

(
for /f "delims=" %%x in ('dir /b /a-d TestMe*.bat') do start "task" cmd /C "%%x"
) | pause

管道内的FOR命令由子CMD在命令行模式下执行,在此模式下,默认情况下命令回显处于启用状态,因此FOR主体内的每个命令都将在执行之前被回显到标准输出(管道),这反过来又馈送pause命令并在创建第一个子进程之前终止其进程,因此,批处理文件的执行无需等待子进程完成即可继续执行.

通过在do后面放置@将关闭FOR主体内部的回显命令,可以轻松解决此问题.

(
for /f "delims=" %%x in ('dir /b /a-d TestMe*.bat') do @start "task" cmd /C "%%x"
) | pause>nul

您可能还想通过将pause命令的输出重定向到nul

来隐藏它

I'm trying to start a fixed number of concurrent batch processes that have similar filenames, all in the same directory:

TestMe1.bat
TestMe2.bat
TestMe3.bat

All batches should start at the same time, and all should complete before the batch continues, e.g. a master.bat:

echo Starting batches

(
start "task1" cmd /C "TestMe1.bat"
start "task2" cmd /C "TestMe2.bat"
start "task3" cmd /C "TestMe3.bat"
) | pause

echo All batches have stopped and we can safely continue

I'm trying to find a way to start all batches in the directory that match TestMe*.bat, so that I don't have to craft a new master.bat file each time. Something like this, but, you know, working:

echo Starting batches

(
for /f "delims=" %%x in ('dir /b /a-d TestMe*.bat') do start "task" cmd /C "%%x"
) | pause

echo All batches have stopped and we can safely continue

Thanks to this and this for getting me this far.

Advice and ideas gratefully received!

解决方案

First you have to understand how this special method of using pipe with the pause command works and why it can be used for waiting for multiple parallel processes.

Taking your first working code sample as the starting point

(
start "task1" cmd /C "TestMe1.bat"
start "task2" cmd /C "TestMe2.bat"
start "task3" cmd /C "TestMe3.bat"
) | pause

It works because each new instance of CMD which is invoked by the start command will be started in a new console with its stdout and stderr redirected to to that new console, so the outputs of the child CMDs will not be redirected to the pipe and so will not be consumed by the pause command which is waiting for input from the pipe.

BUT,

Still each of the processes have inherited the pipe handle, so the handle to the pipe will remain open as long as the child processes are alive.

As a consequence the pause command in the right side of the pipe will remain active, waiting for input from the left side of the pipe until it receives input from the pipe(which will never happen) or all child processes have terminated and closed the handle to the pipe.

So the main CMD instance which is executing your master batch file, is actually waiting for the pause command (right side of the pipe) to terminate which in turn is waiting for child processes (potential pipe writers) to terminate.

Now it becomes clear why your second attempted code involving the FOR loop is not working.

(
for /f "delims=" %%x in ('dir /b /a-d TestMe*.bat') do start "task" cmd /C "%%x"
) | pause

The FOR command inside the pipe is executed by the child CMD in command line mode, In this mode the command echoing in on by default, so every command inside the FOR body will be echoed to standard output(the pipe) before execution, which in turn feeds the pause command and terminate its process before even the first child process is created, Therefor the batch file execution continues without ever waiting for the child processes to finish.

This can be easily resolved by putting the @ after do will turn the command echoing off inside the FOR body.

(
for /f "delims=" %%x in ('dir /b /a-d TestMe*.bat') do @start "task" cmd /C "%%x"
) | pause>nul

You may also want to hide the output of pause command by redirecting it to nul

这篇关于使用文件名掩码启动并发批处理,然后等待它们完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆