这里有一个解决方案,可以很好地处理批处理文件可能调用另一个批处理文件(“嵌套”)。
您可以使用Find命令查找“/c”,如果从“命令提示符”运行批处理文件,则不应该出现此命令:
echo %cmdcmdline% | find /i "/c"
但是,您可以通过使用“查找”命令搜索更长的字符串或批处理文件名来进行更“健壮”的测试。
如果搜索字符串中包含()双引号,则“查找”命令将无法正常工作。为了解决这个问题,您可以使用环境变量替换来“调整”字符串,以便使其与“查找”命令兼容:
set newcmdcmdline=%cmdcmdline:"=-%
通常会返回以下内容:
if the batch-file is run from a "Command Prompt"
newcmdcmdline=-C:\Windows\system32\cmd.exe-
if the batch-file is run by clicking on the the batch-file
(or the batch-file shortcut) from "Windows Explorer"
newcmdcmdline=cmd /c --D:\Path\test.cmd- -
然后您可以使用“查找”功能进行测试,如下所示:
echo %newcmdcmdline% | find /i "cmd /c --"
or
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
接下来,您需要决定是否希望“嵌套”批处理文件的行为表现得像您以与调用批处理文件相同的方式执行它一样,还是希望嵌套批处理文件始终表现得像从“命令提示符”中执行它们。
请注意,如果您正在运行嵌套批处理文件,则可以测试此内容:
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
这个命令总是失败(没有匹配),因为%newcmdcmdline%包含最外层批处理文件的名称,而不是嵌套的批处理文件。
所以第一个解决方案对于调用批处理文件和所有嵌套批处理文件都会产生相同的行为。如果您不调用任何批处理文件,则完美无缺:
在您关心进行此测试的所有批处理文件(调用和嵌套)中添加这些行,通常位于批处理文件的顶部附近(如果您愿意,可以排除echo语句):
if not defined withincmd call :testshell
if %withincmd% EQU 0 echo This batch-file: %~dpf0 was executed directly (from Windows Explorer, ...).
if %withincmd% EQU 1 echo This batch-file: %~dpf0 was executed from within a Command Prompt
rem if %withincmd% EQU 0 pause
接下来,在每个批处理文件中添加testshell子函数:
goto :EOF
:testshell
rem "Nested" batch-files won't see this because withincmd is already defined
if not defined newcmdcmdline set newcmdcmdline=%cmdcmdline:"=-%
set withincmd=1
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
if %errorlevel% EQU 0 set withincmd=0
goto :EOF
您只需要在最外层的批处理文件顶部进行一次对“testshell”的条件调用。
在某些情况下,您可能希望只有从“命令提示符”执行最外层批处理文件与通过单击“Windows资源管理器”中的批处理文件(或批处理文件快捷方式)运行它时表现不同。因此,从“最外层”批处理文件调用的批处理文件将始终以相同的方式运行,无论它们如何运行。
为了使其起作用,您有几个选择:
1)在调用另一个批处理文件之前保存“withincmd”的值,并在被调用的批处理文件返回后恢复“withincmd”的先前值。这对于大多数情况来说有点复杂。
2)在每个批处理文件中使用“全局唯一”变量名称作为“withincmd”。
3)每次需要知道当前批处理文件是如何运行的时候,执行“Find”命令。
4)在进入批处理文件时增加一个变量并在退出批处理文件时减少它,然后仅在计数变量= 1时测试批处理文件如何运行。
方法3是最简单的,但缺点是如果最外层批处理文件是从自身(如递归)或另一个批处理文件中调用的,则测试变量(withincmd)将无法正确设置。
以下是使用方法3的方法:
在您关心进行此测试的所有批处理文件(调用和嵌套)中,添加这些行,通常位于批处理文件的顶部(如果您愿意,可以省略echo语句):
call :testshell
if %withincmd% EQU 0 echo This batch-file: %~dpf0 was executed directly (from Windows Explorer, ...).
if %withincmd% EQU 1 echo This batch-file: %~dpf0 was executed from (or Nested) within a Command Prompt
rem if %withincmd% EQU 0 pause
然后,在每个批处理文件的某个地方添加testshell子函数:
goto :EOF
:testshell
if not defined newcmdcmdline set newcmdcmdline=%cmdcmdline:"=-%
set withincmd=1
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
if %errorlevel% EQU 0 set withincmd=0
goto :EOF
在这种情况下,您需要在每个批处理文件的顶部调用“testshell”一次,然后在从另一个批处理文件返回后再次调用它(或每次需要知道当前批处理文件如何运行时都调用“testshell”)。
以下是使用第4种方法的方法:
在所有您想要进行此测试的批处理文件(包括调用和嵌套的批处理文件)中,添加以下行,通常位于批处理文件的顶部(如果愿意,可以省略echo语句):
if not defined nestinglevel set nestinglevel=0
set /A nestinglevel=nestinglevel+1
call :testshell
if %withincmd% EQU 0 echo This batch-file: %~dpf0 was executed directly (from Windows Explorer, ...).
if %withincmd% EQU 1 echo This batch-file: %~dpf0 was executed from (or Nested) within a Command Prompt
rem if %withincmd% EQU 0 pause
然后,在每个批处理文件中添加testshell子函数:
goto :EOF
:testshell
if not defined newcmdcmdline set newcmdcmdline=%cmdcmdline:"=-%
set withincmd=1
if %nestinglevel% GEQ 2 goto :EOF
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
if %errorlevel% EQU 0 set withincmd=0
goto :EOF
此外,当你退出一个批处理文件以返回调用它的批处理文件时,请记得将变量减少:
set /A nestinglevel=nestinglevel-1
在这种情况下,你需要在每个批处理文件的顶部调用一次“testshell”,然后在从另一个批处理文件返回后再次调用它(或者每次需要知道当前批处理文件的运行方式时都调用“testshell”)。
在所有情况下,使用“test %withincmd%”来确定当前批处理文件的运行方式,就像这样:
if %withincmd% EQU 0 pause
if %withincmd% EQU 1 goto :EOF