Kamal Shankar 快速工具 - 递归执行器






4.15/5 (7投票s)
你是否曾经想要一个程序,能够从用户选择的目录中递归地运行另一个程序,并提供完整的标准输入/输出重定向、程序超时设置等功能?更重要的是,你可以轻松修改源代码以满足自己的需求。Kamal Shankar 为你带来了这样一个快速工具。
- 下载演示可执行文件 - 7.87 Kb
- 下载源代码 - 13.8 Kb
如果你的解压缩程序无法打开上述 ZIP 文件,你可能需要使用 WinZip 9 打开它们。
引言
我是一个工具收藏家——四处搜寻别人写过的工具,以便为我自己的微小需求加以利用……如果工具附带源代码,那更是锦上添花,但这种情况并不常见。
最近,我发现了一些仅有二进制文件的工具,它们只在被调用的目录中运行。我真的很希望它们能够深入到子目录中进行操作。
例如,我有一个很棒的工具,可以计算你传递给它的文件在指定目录中的 MD5 摘要,但它没有允许它递归操作的选项。
我还有许多其他工具,它们都能很好地完成自己的工作,但缺少这个功能。
虽然重写这些工具并不难,但我更喜欢偷懒,于是我想,为什么不写一个快速工具,从我指定的起始目录递归执行这些程序呢?这肯定比重写每一个我想添加此功能的工具要快得多!
经过一小时的快速开发,它就诞生了——RecursiveExecuter。
RecursiveExecuter 的功能列表
- 重定向控制台程序输出的选项。
- 允许用户选择程序将在哪些(子)目录中运行的选项。
- 允许你设置要递归执行的程序的超时时间。(默认情况下是无限)。
- 允许你指定目录通配符,以缩小匹配范围。
- 你可以指定程序参数,并能使用将被操作系统目录(当前匹配到的目录)替换的令牌!
如何使用 RecursiveExecuter
虽然对话框上的选项应该不言自明,但我还是会提及一些细节,这些细节可能会帮助你更好地使用这个小工具。
注意
- 在下面的注释中,“子进程”是指你选择运行的程序。
- 你会遇到一个新的令牌“<>”,这是我选择的一个特殊令牌。你可以在任何你想让RecursiveExecuter放置它要递归进入的操作目录的地方使用这个令牌。
例如,如果你希望当RecursiveExecuter深入到X:\ThisDir时,你的选定程序的参数是
"-l -d:X:\ThisDir"
,当它深入到X:\ThisDir\SubDir时,参数是"-l -d:X:\ThisDir\SubDir"
,那么你在RecursiveExecuter的相应字段中输入以下内容:"-l -d:<>"
。RecursiveExecuter在运行时所做的就是简单地将“
<>
”替换为它刚刚找到的操作目录!我为什么要选择这个令牌? 因为在 Windows 中,它是一个非法的目录名——任何目录都不能包含这两个字符中的任何一个!
- “操作目录”是指RecursiveExecuter在递归过程中当前找到的目录。这与“当前目录”的含义不同,后者是指传递给子进程的目录变量(由“Current Dir Value”字段指定)。
但是,如果你将“Current Dir Value”字段的值保留为默认的“<>”,那么两者将具有相同的值。
例如,如果RecursiveExecuter刚刚遇到了目录X:\RootDir\SubDir\AnotherDir,那么操作目录就是X:\RootDir\SubDir\AnotherDir。
RecursiveExecuter将令牌“<>”解释为操作目录的含义。
以下是对话框字段的详细说明
- 程序选项:
- Redirect STDIO:此选项允许你将控制台程序的输出重定向/捕获到一个你指定的文本文件中。默认情况下它是未勾选的,当你勾选它时,将弹出一个文件对话框,你可以在其中选择输出文件名,输出将被重定向到该文件。
注意:勾选此选项时,子进程窗口也将隐藏,也就是说,你将看不到通常会看到的控制台窗口。
- Confirm new entry:由于此程序会递归进入目录,你可能希望过滤掉一些不希望程序对其进行操作的目录。
勾选此框后,每当RecursiveExecuter切换到新目录时,它都会询问你是否允许子进程在该目录中运行。
如果你想跳过在该目录中进行操作,只需在对话框中选择“否”即可。
- Timeout (ms):默认情况下,它是-1,表示在运行的进程上处于无限等待状态(这意味着RecursiveExecuter将耐心等待子进程完成)。建议将其保持原样。
但是,你可能有自己的理由来调整RecursiveExecuter等待子进程完成的时间。如果子进程在字段中指定的时间量后仍然处于活动状态,RecursiveExecuter将简单地将其终止。
- Directory wildcard:如果你想微调RecursiveExecuter将要进入的目录列表,此选项会很有用。
默认情况下,它是空的,这意味着RecursiveExecuter将进入“Select the starting directory”字段中指定的(子)目录及其所有子目录。
除了以上之外,它将被解释为 Windows Find 的方式。例如,值为 '*' 将使RecursiveExecuter仅在指定目录的子目录中运行,或者值为 'r*' 将匹配所有以 'r' 开头的(子)目录。
- Current Dir value:子进程是使用
CreateProcess()
调用创建的。CreateProcess()
的一个参数是LPCTSTR lpCurrentDirectory
,它指定子进程的当前驱动器和目录。虽然此值可以为
NULL
,但许多程序在传递有意义的值(通常是当前工作目录)时运行得更好。事实上,大多数控制台程序都通过此参数传递的目录执行所需的操作。
你可以将此字段视为创建程序快捷方式时填写的“Working Directory”或“Start In”字段。
如果不确定,应将其保留为默认值“<>”。
- Redirect STDIO:此选项允许你将控制台程序的输出重定向/捕获到一个你指定的文本文件中。默认情况下它是未勾选的,当你勾选它时,将弹出一个文件对话框,你可以在其中选择输出文件名,输出将被重定向到该文件。
- 执行选项
- Select the program you want to execute : 选择你要递归执行的程序的路径。直接输入(必须是完整限定文件名),或使用旁边的Browse按钮。
这个程序将被创建为子进程。
- Select the starting directory : 选择你希望RecursiveExecuter开始递归的起始目录。
- Executable arguments : 输入你希望传递给子进程的参数(命令行选项)。
同样,如果你想将操作目录传递给命令行,只需将“<>”令牌(不带引号)放在相应位置即可!
- Select the program you want to execute : 选择你要递归执行的程序的路径。直接输入(必须是完整限定文件名),或使用旁边的Browse按钮。
关注点
CreateProcess() 的行为
虽然 MSDN 的“INFO: Understanding CreateProcess
and Command-line Arguments”的“Case 3”中对此有详细说明,但我仍将在此简要提及。
让我们更详细地查看CreateProcess()
的原型。
BOOL CreateProcess( LPCTSTR lpApplicationName, // name of executable module LPTSTR lpCommandLine, // command line string ....);
要创建控制台程序,我们可以将lpApplicationName
设置为NULL
,但lpCommandLine
必须至少包含(完整限定的)进程文件名。额外的命令行参数可能像往常一样跟在后面。
但是,如果我们把完整限定的程序名传递给lpApplicationName
,而把命令行的其余部分传递给lpCommandLine
,那么控制台进程可以被创建,但main()
的参数将不匹配。
为了说明我的意思,假设我们有一个控制台程序"prog.exe"。它接受许多命令行开关,其中一个开关是"-h -m simple"
,它会打印出一个简单的帮助页面。
如果我们使用CreateProcess()
像这样创建进程:
.... char szArgs[MAX_ARGS]; lstrcpy(szArgs,"-h -m simple"); CreateProcess("X:\\prog.exe",szArgs,...);
那么进程将被创建,但命令行参数将具有以下值:
argv[0] == "-h" argv[1] == "-m" argv[2] == "simple"
但当然,ANSI 规范要求值看起来像:
argv[0] == "X:\\prog.exe" argv[1] == "-h" argv[2] == "-m" argv[3] == "simple"
我们作为优秀的程序员,一直遵循 ANSI 规范进行编码。所以,任何遵循此 ANSI 规范的控制台程序都会出现问题。
现在,RecursiveExecuter在默认启动程序时会考虑这一点,但如果你有不遵循 ANSI 规范,而是依赖CreateProcess
这种行为的程序,你可以手动删除自动添加到RecursiveExecuter的“Executable arguments”字段中的程序名,一切都会正常。
BUG
有时,在运行启用了Redirect STDIO的控制台应用程序时,可能会出现“挂起”RecursiveExecuter的情况。但是,在终止子进程后,RecursiveExecuter将恢复任务。
令人惊讶的是,字段设置的组合完全相同,只是Redirect STDIO(现在已禁用)除外,不会产生任何问题。
修复这个问题需要一些时间,但我认为这与管道有关。如果你们中的任何人能发现问题(并修复它?),请告诉我。
总结
这个工具对我来说运行良好,我也没有见过它运行得不好。如果它对你有用,并且你喜欢它,请评分,然后幸福地生活,并记住是我写的。
如果你有 bug 报告、功能请求或任何其他问题,请在此消息板上发帖,或给我打个电话(发邮件给我)。
如果这个程序在你的电脑上制造了一个黑洞或让你隐形了,请记住,它是被一个同时也在观看Whose Line Is It Anyway的人编写的。你已被警告。去责怪 Drew 吧 ;)
历史
2004/04/20 - 初始发布。