Вот решение, которое должно работать хорошо и учитывать вероятность того, что пакетный файл может вызвать другой пакетный файл («вложенный»).
Вы можете использовать Find для поиска «/ c», которого не должно быть, если пакетный файл запускается из «Командной строки»:
echo %cmdcmdline% | find /i "/c"
Но вы могли бы сделать более «надежный» тест, используя Find для поиска более длинной строки или имени пакетного файла.
Команда "Найти" не будет работать должным образом, если в строке поиска есть (") двойные кавычки. Чтобы обойти это, вы можете использовать подстановку переменных среды, чтобы" скорректировать "строку, чтобы она хорошо работала с Find:
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
Вы можете сделать условный вызов «testhell» только один раз, вверху самого внешнего пакетного файла.
В некоторых ситуациях может потребоваться, чтобы только «самый внешний» пакетный файл вел себя по-другому, если он выполняется из «командной строки», и если он запускается нажатием на пакетный файл (или пакетный ярлык файла) из "Проводника Windows". Таким образом, пакетные файлы, вызываемые из «самого внешнего» пакетного файла, всегда будут вести себя одинаково независимо от того, как они выполняются.
Чтобы это работало, у вас есть несколько вариантов.
1) Сохраните значение «insidecmd» перед вызовом другого пакетного файла и восстановите предыдущее значение «insidecmd» после возврата вызванного пакетного файла. Это немного сложно для большинства случаев.
2) Используйте «глобально уникальное» имя переменной для «withincmd» в каждом пакетном файле.
3) Выполняйте команду «Найти» каждый раз, когда вам нужно узнать, как был запущен текущий пакетный файл.
4) Увеличивать переменную при входе в пакетный файл и уменьшать ее при выходе из пакетного файла, а затем проверять только, как запускался пакетный файл, если count-variable = 1
Метод 3 является самым простым, но имеет недостаток в том, что если самый внешний пакетный файл вызывается из самого себя (как в рекурсии) или из другого пакетного файла, тестовая переменная (в пределах cmd) не будет правильно установлена.
Вот как это сделать, используя метод 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
В этом случае вам придется вызывать «тестовую оболочку» один раз, вверху каждого пакетного файла, затем снова после того, как вы вернулись из вызова другого пакетного файла (или вызывать «тестовую оболочку» каждый раз, когда вам нужно знать как был запущен текущий пакетный файл).
Вот как это сделать, используя метод 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
В этом случае вам придется вызывать «testhell» один раз, вверху каждого пакетного файла, а затем снова после того, как вы вернулись из вызова другого пакетного файла (или вызывать «testhell» каждый раз, когда вам нужно знать как был запущен текущий пакетный файл).
Во всех случаях тестируйте% withincmd%, чтобы определить, как был запущен текущий пакетный файл, например:
if %withincmd% EQU 0 pause
if %withincmd% EQU 1 goto :EOF