以递归方式查找调用的批处理文件

时间:2013-02-15 10:50:26

标签: batch-file

我们当前的构建系统是从“主”批处理文件调用的大量批处理文件。如何查找从“主”批处理文件调用的所有批处理文件?

不幸的是,存储库还包含许多其他批处理文件,我不能只列出工作副本中的所有批处理文件。

我不太关心“模拟”真正的执行。如果我得到一个可能从主批处理文件调用的所有文件的列表,那就没问题。

有299个文件,所以我不想在每个文件中添加一个回音“”。

使用“call xyz.bat”调用引用的批处理文件,即相对路径。有时批处理文件会改变当前的工作目录,如下所示:

cd client
call mk.bat
cd ..

pushd client\install
call prepare.bat
popd

编辑:添加了示例

2 个答案:

答案 0 :(得分:2)

Yuck - 由于以下几个原因,这个问题几乎不可能完全解决:

1)批处理文件可以通过多种机制“调用”:

  • CALL scriptName

  • 管道,例如:scriptName | findstr ...

  • FOR / F,例如:for /f ... in ('scriptName ...') do ...

  • CMD,例如:cmd /c scriptName ...%comspec% /c scriptName

  • START,例如start "" scriptName ...

2)任何上述结构都可以存在而不是对批处理脚本的“调用”。例如,CALL可用于调用标签或执行命令。 FOR / F可用于解析字符串。等

3)无论使用哪种“呼叫”机制,“呼叫”目标都可以用变量代替字符串文字来表示。例如:

set "myScript=ScriptName"
REM the SET may not be anywhere near the CALL
call %myScript%

4)脚本名称和路径可能不会出现在代码中。它可以从文件系统中动态读取,也可以通过逻辑导出。

5)实际调用本身可以作为值嵌入变量中。任何呼叫机制都是如此。例如:

set "myCommand=CALL"
%myCommand% ScriptName

6)正如您在问题中所指出的,脚本的路径可能是相对的,脚本可能会更改当前目录。或者“调用”可能依赖于PATH环境变量。

7)任何“被叫”脚本本身都可以“调用”另一个脚本。


您可以使用FINDSTR查找任何呼叫机制,您可能会找到大多数“呼叫”。但可能会有 许多 误报。您可以添加/N开关,为每个匹配的行添加前缀和行号。然后,您需要在文本编辑器中手动检查每个匹配的行,看看它是否是您感兴趣的“调用”。

findstr /nir /c:"\<call\>" /c:"|" /c:"for  */f " /c:"\<cmd\>" /c:"\<%comspec%\>" /c:"\<start\>" *.bat

可能有很多误报,你可能最好手动跟踪整个脚本的逻辑:-(这尤其正确,因为无法保证FINDSTR会找到所有“调用”,因为调用本身可以被隐藏在变量后面。

答案 1 :(得分:1)

您可以在每个批处理文件之前添加日志记录。我知道你说过你不愿意,但它并不像你想象的那么难。

@echo off
:: addlogging.bat patch|unpatch
::
:: addlogging.bat patch
::    finds every .bat file in the current directory and every subdir
::    beyond, and patches each, prepending an echo to a log file
::
:: addlogging.bat unpatch
::    finds every .bat file in the current directory and every subdir
::    beyond, and removes the logging patch

setlocal

if #%1==#patch goto next
if #%1==#unpatch goto next
goto usage

:next
for /f "delims=" %%I in ('dir /s /b *.bat') do (
    if not "%%I"=="%~f0" (
        if #%1==#patch (
            set /p I="Patching %%I... "<NUL
            echo @echo %%time%% %%~f0 %%* ^>^> "%%userprofile%%\Desktop\%%date:/=-%%.log">"%%~dpnI.tmp"
        ) else (
            set /p I="Unpatching %%I... "<NUL
        )
        findstr /v "^@echo.*time.*~f0.*>>" "%%I">>"%%~dpnI.tmp"
        move /y "%%~dpnI.tmp" "%%I">NUL
        echo Done.
    )
)
goto :EOF

:usage
echo usage: %~nx0 patch^|unpatch