在Windows批处理文件中运行另一个程序而不创建子进程

21

我有一个Subversion服务器,其中有一个后提交挂钩(post-commit hook)用于执行某些操作。

我希望检入过程快速完成,而不是等待挂钩脚本运行。但按照设计,Subversion后提交挂钩脚本将一直运行,直到所有子进程都退出,因此在挂钩批处理文件中使用类似以下命令:

start another_prog...

没有任何用处。

因此,我想知道如何在Windows批处理文件中运行另一个程序,而不创建子进程或使子进程与父进程分离。


你能澄清一下你试图解决的问题吗?难道Subversion提交后钩子等待所有进程退出是真的吗?为什么start cmd /c startWebLogic.cmd不起作用? - Cheeso
4
由于 SVN 的设计,start cmd /c 命令无法生效,因为 SVN post-commit hook 会等待钩子和由钩子创建的子进程退出。 我已经找到了解决方案,请参考:http://svn.haxx.se/users/archive-2008-11/0301.shtml。 - zhongshu
7个回答

26

同步。只有在关闭第一个记事本之后,第二个记事本才会启动。

notepad.exe c:\temp\a.txt
notepad.exe c:\temp\b.txt

异步:即使您没有关闭第一个记事本,第二个记事本也会启动。

start notepad.exe c:\temp\a.txt
start notepad.exe c:\temp\b.txt

关于start命令的更多信息:
http://www.robvanderwoude.com/ntstart.php

编辑:原帖作者@zhongshu在其他地方发表了以下评论,我只是将其复制到这里:

使用“start cmd /c”无效,因为SVN post-commit钩子将等待钩子和由钩子创建的子进程退出。这是SVN的设计。 我找到了一个解决方案,请参考:http://svn.haxx.se/users/archive-2008-11/0301.shtml

假设他知道自己在说什么,那么我错了,并且不配得到。


反转:如果你想打开/运行100个bat/cmd进程(像我一样),并使它们成为父进程的子进程(例如,为了方便关闭)- 将命令放入一个bat/cmd中,并从另一个bat/cmd启动它(而不是通过双击)。我写这篇文章是因为我在搜索反向意图时没有找到任何东西。 - mevsme

14

我找到了一种解决我的问题的方法,编译以下C代码并将可执行文件命名为runjob.exe,然后在hook批处理文件中使用“runjob another_prog”,现在可以正常运行。

#include <windows.h> 
#include <stdio.h> 
#include <tchar.h> 
int _tmain() 
{ 
    char * pCmd = ::GetCommandLine(); 
    // skip the executable 
    if (*pCmd++ == L'"')
    {
        while (*pCmd++ != L'"'); 
    }
    else 
    {
        while (*pCmd != NULL && *pCmd != L' ') 
            ++pCmd; 
    }

    while (*pCmd == L' ')
        pCmd++; 

    STARTUPINFO si; 
    ZeroMemory( &si, sizeof(si) ); 
    si.cb = sizeof(si); 
    PROCESS_INFORMATION pi; 
    ZeroMemory( &pi, sizeof(pi) ); 

    // Start the child process. 
    BOOL result = CreateProcess 
    ( 
        NULL, // No module name (use command line) 
        pCmd, // Command line 
        NULL, // Process handle not inheritable 
        NULL, // Thread handle not inheritable 
        FALSE, // Set bInheritHandles to FALSE 
        DETACHED_PROCESS, // Detach process 
        NULL, // Use parent's environment block 
        NULL, // Use parent's starting directory 
        &si, // Pointer to STARTUPINFO structure 
        &pi // Pointer to PROCESS_INFORMATION structure (returned) 
    ); 
    if (result) return 0; 

    char msg[2048]; 
    FormatMessage 
    ( 
        FORMAT_MESSAGE_FROM_SYSTEM, 
        NULL, 
        ::GetLastError(), 
        MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), 
        msg, sizeof(msg), 
        NULL 
    ); 
    fputs(msg, stderr); 
    _flushall(); 

    return -1; 
} 

非常感谢提供正确的解决方案!虽然创建自己的程序来执行其他程序仍然有点不舒服,但比使用计划任务等方式好100倍。谢谢谢谢谢谢。 - honzajscz
3
这是源代码的编译执行文件链接:https://mega.nz/#!u8tD0YAY!OuULXWhzG4VThwLAbkjpRdTfg6XLgxFmmpNP2hnzb1w - Håkon Egset Harnes
1
那么,为another_prog提供命令行参数的一些规定怎么样?否则,我就得编写另一个批处理脚本来调用带有参数的exe文件。 - evandrix

8

您可以创建一个定时任务,执行批处理脚本或其他长时间运行的可执行文件。将其设置为在过去运行一次,并不设置在没有更多运行计划时删除该任务。然后,在您的Subversion钩子脚本中,添加以下行:

schtasks /run /tn NameOfYourTaskHere

我进行了一项测试以确认,即通过让我的计划任务运行Notepad++,Notepad++可执行文件显示为svchost.exe的子进程,而不是我从schtasks命令执行的cmd.exe窗口。


这对于Windows上的SVN提交后操作非常有效。我们之前使用的PowerShell脚本会导致提交到svn时出现明显的延迟。现在有了定期任务,提交立即完成并且任务在后台执行。schtasks /run /tn NameOfTask是最佳解决方案。 - truemedia

6

使用:

start cmd /c "your command"

欢呼。

在许多情况下,您应该能够省略“cmd /c”(请参见Corey Trager的回答)。 - jdigital
2
这种方法在Windows上不适用于SVN提交后钩子。它仍然会等待子进程完成。请参见Corey Trager的答案。 - truemedia

1

尝试使用 cmd /c "你的命令"


1
不,cmd /c 没有用处,svn 会等待“your command”完成。 - zhongshu

1
你可以使用Windows任务计划程序命令行界面"schtasks /run"来启动运行"another_prog"的作业吗?你需要提前创建这个作业。以前Windows(NT)资源工具包中有一个名为"SOON"的程序,它可以为"AT"命令调度程序创建动态条目,以便在几分钟内运行作业,而不需要提前设置作业,只需稍加搜索即可找到它。

0

您可以创建一个混合批处理/JScript文件(即能够运行嵌入式JScript的批处理文件),其中JScript部分将使用shell.Run(prog, 0, false)以分离模式运行another_prog

@if (@X)==(@Y) @end /* JScript comment
    rem put any batch code that runs before another_prog here
    @cscript //E:JScript //nologo "%~f0" "another_prog" 0 false
    rem put any batch code that runs after another_prog here

    exit /b %errorlevel%
@if (@X)==(@Y) @end JScript comment */

var ARGS = WScript.Arguments;
var shell = new ActiveXObject("WScript.Shell");
shell.Run(ARGS.Item(0),ARGS.Item(1),ARGS.Item(2));`

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