ERRORLEVEL vs %ERRORLEVEL% vs восклицательный знак ERRORLEVEL восклицательный знак

Я думаю, что у меня есть общее представление об ERRORLEVEL и %ERRORLEVEL%, но !ERRORLEVEL! смущает меня.

Я делаю скрипт, который вызывает исполняемый файл, затем список задач, чтобы увидеть, работает ли он, затем тасккилл, чтобы убить его, если это так, а затем пытаюсь вывести уровни ошибок и повторять для других исполняемых файлов, и я понимаю, что я действительно не понимаю уровни ошибок в пакете.

Я установил переменную, равную !errorlevel! затем использовал эту переменную без кавычек в эхе, и переменная изменилась с одного uint16 на другой uint16, когда после набора произошла ошибка, например, это ссылка на реальную вместо копии. Я хочу копию. Кто-нибудь может объяснить разницу между этими парнями?


Обновление: вот фрагмент, над которым я работаю.

for %%P in (%executableList%) do (
   echo ----------------------------------------------------------------------------------       
    set exeErrorlevel=0
    set running=false

    start %%~fP  
    set exeErrorlevel=!ERRORLEVEL!

    rem for debugging purposes
    echo %%~nP%%~xP older errorlevel %ERRORLEVEL%       
    echo %%~nP%%~xP newer errorlevel !ERRORLEVEL!        
    echo before tasklist running var is : !running!

    tasklist /FI "IMAGENAME eq %%~fP" | find /I /N /C  "%%~fP" >nul && set running=true

    echo after tasklist is running var is: !running!

    if !running! equ true ( 
       echo %%~nP%%~xP Program is running
       taskkill /F /IM %%~nP%%~xP /T
       echo %%~nP%%~xP Program was killed          

       if !exeErrorlevel! == 0 (
           echo %passString% %%~nP%%~xP process was started and killed safely 
           echo %passString% %%~nP%%~xP process was started and killed safely >>%outputfile%
       ) else ( 
           echo %failString% %%~nP%%~xP process was killed with errorcode !exeErrorlevel!
           echo %failString% %%~nP%%~xP process was killed with errorcode !exeErrorlevel! >>%outputfile%                  
       )         
    ) else (             
         if !exeErrorlevel! == 0 (
             echo %passString% %%~nP%%~xP process exited safely
             echo %passString% %%~nP%%~xP process exited safely >>%outputfile%
         ) else (                 
             taskkill /F /IM %%~nP%%~xP /T
             echo %failString% %%~nP%%~xP process abruptly exited with errorcode !exeErrorlevel! 
             echo %failString% %%~nP%%~xP process abruptly exited with errorcode !exeErrorlevel! >>%outputfile%                  
         )                    
    )

    echo. >>%outputfile%


)

Мне нужно убедиться, что exeErrorlevel имеет копию уровня ошибок в определенный момент времени - я хочу фиксировать ошибки только из exe, а не из успеха/неудачи списка задач/поиска/задачи. Я обеспокоен тем, что exeerrorlevel из-за отложенного расширения обращается к отложенному уровню ошибок при выполнении. возможно, вместо этого следует установить exeErrorlevel=%errorlevel%. В строке, где я повторяю старые и новые переменные, обычно возвращаются разные целые числа? Во всех моих тестовых прогонах %errorlevel% обычно возвращает 0, тогда как !errorlevel! постоянно отличен от нуля для исполняемых файлов с неверными кодами выхода.


person codeMetis    schedule 23.03.2017    source источник
comment
Из описания кажется, что вы назначили var=!errorlevel! без активного отложенного расширения, а затем выполнили echo %var% с активным отложенным расширением, но, не видя кода, мы просто предполагаем.   -  person MC ND    schedule 23.03.2017
comment
Достаточно уверен ! вокруг переменной ничего не делает для расширения переменной, если отложенное расширение не активно, оно будет обрабатывать его как строку ..... У меня есть setlocal enableextension delayedexpansion в верхней части моей летучей мыши. Все, что я хочу знать, это разница между теми тремя наверху. Я хочу знать, как они работают.   -  person codeMetis    schedule 23.03.2017


Ответы (1)


Уровень ошибки

errorlevel — это имя динамической переменной (она не помещается в блок окружения, а хранится в памяти), которая хранит код завершения предыдущего выполненного процесса/команды (если она устанавливает это значение, читайте здесь, здесь, здесь и здесь).

Команда if позволяет использовать синтаксис if errorlevel n для проверки того, является ли значение переменной errorlevel больше или равным n, не привлекая пакетный синтаксический анализатор для извлечения значения переменной.

Но если мы заставим пакетный синтаксический анализатор работать со значениями переменных, %errorlevel% будет просто ссылкой на значение, хранящееся в переменной, операция чтения. Точно так же, как !errorlevel!. Основное различие между ними заключается в том, что когда значение извлекается в зависимости от правил расширения переменной. .

Существует большая разница между использованием if errorlevel и получением значения переменной:

  • Операция чтения переменной проверит, содержит ли блок окружения переменную с указанным именем.
  • Конструкция if не пройдет этот тест.

Если вы сделаете что-то вроде set errorlevel=10, динамическое значение errorlevel не будет получено с помощью %errorlevel% или !errorlevel!, так как значение, установленное в среде, скроет динамическое значение. Но так как if errorlevel не читает блок окружения, а напрямую читает внутреннюю переменную, содержащую значение, то работать будет без проблем.

Переменные

Пакетный синтаксис не включает возможность иметь более одной переменной, указывающей на одно и то же значение в памяти таким образом, что если одна из переменных изменит свое значение, другая отразит это изменение.

Это поведение можно смоделировать, правильно используя различные этапы раскрытия переменных, правильно устанавливая переменную в имя другой и заставляя пакетный синтаксический анализатор выполнять два прохода над командой, чтобы первая переменная разрешалась в имя второй, и это к реальной стоимости.

Ваша проблема

Упрощенный (даже не рабочий) код только для анализа

 1  for %%P in (%executableList%) do (
 2  
 3      start %%~fP  
 4      set exeErrorlevel=!ERRORLEVEL!
 5  
 6      echo %%~nP%%~xP older errorlevel %ERRORLEVEL%       
 7      echo %%~nP%%~xP newer errorlevel !ERRORLEVEL!        
 8      ....
 9      if !running! equ true ( 
10         taskkill /F /IM %%~nP%%~xP /T
11         if !exeErrorlevel! == 0 (
12          ....
13         ) else ( 
14             echo process killed with errorcode !exeErrorlevel!
15         )         
16      ) else (             
17           if !exeErrorlevel! == 0 (
18             ....
19           ) else (                 
20               taskkill /F /IM %%~nP%%~xP /T
21               echo process abruptly exited with errorcode !exeErrorlevel! 
22           )                    
23      )
  • строка 1: анализируется код в предложении do, весь код. Любая операция чтения переменной %var% удаляется из кода и заменяется значением внутри переменной перед началом выполнения. Это означает, что если переменная изменит свое значение, вы не сможете получить измененное значение, так как операции чтения не существует, только начальное значение в переменной.

  • строка 3: исполняемый файл запускается в отдельном процессе, не дожидаясь завершения процесса. Это важно? См. следующую строку

  • строка 4: текущее (используемое отложенное расширение) значение переменной errorlevel извлекается и сохраняется в переменной exeErrorlevel. НО сохраненное значение НЕ является errorlevel, возвращаемым исполняемым файлом (отдельный процесс, не дожидаясь его завершения, как мы узнаем, что такое exit code = errorlevel?), а код выхода команды start.

  • строка 6: поскольку операция чтения %errorlevel% была удалена, эта строка будет отображать значение, которое было сохранено в переменной errorlevel до начала выполнения предложения do.

  • строка 7: извлекается текущее значение переменной errorlevel. И здесь у нас могут возникнуть проблемы. Как называется исполняемый скрипт? Есть разница между .bat и .cmd. В случае успеха команда set в строке 4 очистит (установит 0) переменную errorlevel, если это файл .cmd, но не изменит errorlevel, если это файл .bat.

  • строки 11, 14, 21: как видно, переменная exeErrorlevel не содержит допустимого значения. И нет, изменение строк на !errorlevel! приведет не к коду выхода процесса, а к коду выхода taskkill.

Чтобы иметь возможность получить код выхода / уровень ошибки процесса, нам нужно дождаться его завершения. Если вам нужно запустить процесс, если он продолжает работать, убейте его и в обоих случаях получите код выхода, напрямую вызовите исполняемый файл или используйте start "" /wait programName И запустите процесс уничтожения параллельно (например, start /b "" monitor.bat programName или что-то подобное перед запуском программы ). Основной процесс будет ждать и получит код выхода. Процесс монитора обрабатывает уничтожение.

person MC ND    schedule 23.03.2017
comment
Спасибо за ваши ссылки. Я обновил вопрос своим кодом и понимаю, что, возможно, я неправильно понимаю расширение отложенной переменной. Спасибо за уточнение, что set хранит не указатель, а копию. - person codeMetis; 24.03.2017
comment
строка 3: многие из моих exe-процессов не заканчиваются. Я думал, что ждать их было бы глупо. строка 4: некоторые заканчиваются. если процесс завершается сам по себе, не будет ли этот код распространяться на команду запуска, и, поскольку между строками 3 и 4 не происходит ничего другого, что могло бы очистить код выхода, не должен ли это быть уровень ошибки, возвращаемый exe, если он вышел, и 0 если нет? строка 6: если это до do, если я изменю значение в одной итерации, будет ли оно другим, когда do будет оцениваться до начала следующей итерации? или все это происходит один раз раньше и, следовательно, одно и то же значение для всех итераций. - person codeMetis; 27.03.2017
comment
строка 11,14,21: поэтому я пытался сохранить уровень ошибки ранее. Также я заметил, что часто !exeErrorLevel! будет оцениваться не как 0, но затем в stdout он печатает 0. Я выполню ваши предложения, но что делает перед командой запуска? - person codeMetis; 27.03.2017
comment
@ user2309274, строка 4 Нет, после команды start (без /wait) вы получаете errorlevel start, а не программу. строка 6 как сказано, после анализа команды full for не выполняется операция чтения %var%, только значения, содержащиеся в переменных во время анализа, то же самое начальное значение для всех итераций. команда start обрабатывает свой первый аргумент в кавычках как заголовок окна, если вашей команде нужны кавычки (например, пробелы в имени файла, пути, ...), вам нужно включить заголовок окна ("" = пустой заголовок окна) - person MC ND; 27.03.2017