Что нового

Не работают некоторые инструкции интерпретатора cmd.exe

tech-gs

Знающий
Сообщения
54
Репутация
5
При запуске следующего кода:

Код:
RunWait('"' & @COMSPEC & '" /C "echo off && set VAR=ABC && echo VAR=%VAR% && pause && exit"')


в cmd-окне вместо ожидаемого VAR=ABC, получаю VAR=%VAR%.
Полагаю, что дело не в AutoIt, т.к. запуск того же самого из командной строки выдает те же результаты. Если перенести команды в .bat или .cmd - работает как и ожидается.
Подскажите, что нужно исправить, чтобы заработали такие команды как set, echo, ...?
 

Yuri

AutoIT Гуру
Сообщения
737
Репутация
282
Мне вот тоже интересно стало.
Может, как выход, не использовать set, а заранее присвоить переменным значения?

Ну вот как-то так:
Код:
$SET_VAR_1 = "ABC"
$SET_VAR_2 = 12
$SET_VAR_3 = 3
$SET_VAR_4 = "notepad.exe"

$str1 = "echo off" & " &&"
$str2 = "echo VAR1 = " & $SET_VAR_1 & " &&"
$str3 = "echo VAR2 = " & $SET_VAR_2 & " &&"
$str4 = "echo VAR3 = " & $SET_VAR_3 & " &&"
$str5 = "echo REZULT = " & ($SET_VAR_2/4.5+$SET_VAR_3) & " &&"
$str6 = "pause" & " &&"
$str7 = $SET_VAR_4 & " &&"
$str8 = "pause" & " &&"
$str9 = "exit"

RunWait(@ComSpec & " /c " & $str1 & $str2 & $str3 & $str4  & $str5  & $str6 & $str7 & $str8 & $str9)
 
Автор
T

tech-gs

Знающий
Сообщения
54
Репутация
5
Garrett
Получается, инструкция echo не отрабатывает? Вместо нее set?


Добавлено:
Сообщение автоматически объединено:

Yuriy
Я привел всего лишь простенький пример нерабочего кода. В реальной программе мне нужно вернуть в переменную код возврата запущенной программы или значение ERRORLEVEL, а этого заранее не сделаешь, поэтому твой способ не подойдет.
Есть несколько способов как сделать по другому, например мне предлагали формировать файл cmd на лету и запускать его:

Код:
$text= _
'echo off' & @CRLF & _
'set VAR=ABC' & @CRLF & _
'echo Переменная VAR=%VAR%' & @CRLF & _
'pause' & @CRLF & _
'exit'

$file = FileOpen(@TempDir&'\file.bat',2)
FileWrite($file, $text)
FileClose($file)

Run(@TempDir&'\file.bat')


Здесь все работает, но не получается вывести кирилические сообщения в DOS-окне.
 
Автор
T

tech-gs

Знающий
Сообщения
54
Репутация
5
Garrett
А можно вывести в одной строке некоторое сообщение и значение переменной VAR (например, аналог команды: echo Код возврата - %VAR%) ?
 
Автор
T

tech-gs

Знающий
Сообщения
54
Репутация
5
Прошу ответить еще на один вопрос.
Запускаю из DOS-сессии программу Updater.exe (скачка антивирусных баз Касперского, после работы устанавливает ERRORLEVEL в определенное значение, в приведенных примерах д.б. ERRORLEVEL=15). В приведенном ниже примере (базы не скачиваются, только выводится справка) после отработки Updater.exe происходит выход из DOS-сессии без выполнения последующих инструкций, но RunWait возвращает 15:

Код:
RunWait('"' & @COMSPEC & '" /C "echo off && "Updater.exe" -h && set RET=%ERRORLEVEL% && echo Код возврата - %RET% && pause && exit /b %RET%"')


Если Updater.exe запускать через start, то выполнение инструкций после Updater.exe продолжается, но ERRORLEVEL в 15 не устанавливается:

Код:
RunWait('"' & @COMSPEC & '" /C "echo off && start /b /wait /d".\" Updater.exe -h && set RET=%ERRORLEVEL% && echo Код возврата - %RET% && pause && exit /b %RET%"')


Если любой пример трансформировать в cmd-файл (test1.cmd, test2.cmd) и запустить его, то отрабатываются все инструкции и Updater.exe устанавливает ERRORLEVEL=15.

Можно ли все-таки реализовать RunWait('"' & @COMSPEC & '" /C "echo off && ...) чтобы отработали все инструкции и был возвращен результат работы программы?

Файл Updater.exe прикрепить не могу из-за ограничения в 200kb. Взять его можно здесь - http://utils.kaspersky.com/updater/updater_for_windows_v.3.5.0.34.zip
 

Yuri

AutoIT Гуру
Сообщения
737
Репутация
282
Здесь все работает, но не получается вывести кирилические сообщения в DOS-окне.
Код:
#include <Encoding.au3>

$text= "echo off" & @CRLF
$text&= _Encoding_ANSIToOEM("set VAR=Русский - Russian") & @CRLF
$text&= _Encoding_ANSIToOEM("echo Переменная VAR = %VAR%") & @CRLF
$text&= _Encoding_ANSIToOEM("pause") & @CRLF
$text&= _Encoding_ANSIToOEM("exit")

$file = FileOpen(@ScriptDir&"\file.bat",2)
FileWriteLine($file, $text)
FileClose($file)

Run(@ScriptDir&"\file.bat")

Библиотека для работы с кодировками строк Encoding.au3:
http://autoit-script.ru/index.php?action=downloads;sa=view;down=6
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
tech-gs [?]
А можно вывести в одной строке некоторое сообщение и значение переменной VAR (например, аналог команды: echo Код возврата - %VAR%) ?
Боюсь, в командной строке не получится, нужно bat писать. Хотя могу и ошибаться. :scratch:
 

Morock

Новичок
Сообщения
3
Репутация
1
tech-gs сказал(а):
При запуске следующего кода:

Код:
RunWait('"' & @COMSPEC & '" /C "echo off && set VAR=ABC && echo VAR=%VAR% && pause && exit"')


в cmd-окне вместо ожидаемого VAR=ABC, получаю VAR=%VAR%.
Полагаю, что дело не в AutoIt, т.к. запуск того же самого из командной строки выдает те же результаты. Если перенести команды в .bat или .cmd - работает как и ожидается.
Подскажите, что нужно исправить, чтобы заработали такие команды как set, ...?

а если вот так?

Код:
RunWait('"' & @COMSPEC & '" /C /V:ON "echo off && set VAR=ABC && echo VAR=%VAR% && pause && exit"')


должно работать


для полного понимания механики вдумчиво курим хелп
Код:
>help set
...
Наконец, добавлена поддержка связывания времени выполнения для переменных среды
окружения. По умолчанию эта поддержка отключена. Ключ /V командной строки
CMD.EXE позволяет включать и выключать ее. Для вызова справки, наберите CMD /?

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

    set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "%VAR%" == "after" @echo Тело внутреннего оператора сравнения
    )

Данное сообщение не будет выводиться, т.к. %VAR% в ОБОИХ выражениях IF
подставляется в момент первого использования в первом IF, в том числе и в тело
первого ветвления IF, которое является составным выражением. В IF внутри
составного выражения в действительности сравниваются значения "before" и
"after", что заведомо ложно. Следующий пример демонстрирует подобную ошибку:

    set LIST=
    for %i in (*) do set LIST=%LIST% %i
    echo %LIST%

в данном случае список файлов текущей папки никогда не будет построен. Вместо
этого, значением переменной LIST будет имя последнего найденного файла.
И вновь, это случилось потому, что %LIST% подставляется всего один раз -
в момент обработки выражения FOR, когда список еще пуст.
Фактически, приведенный фрагмент эквивалентен следующему примеру:

    for %i in (*) do set LIST= %i

в котором имя последнего найденного файла сохраняется в переменной LIST.

Связывание времени выполнения для переменных среды окружения происходит при
использовании специального символа (восклицательного знака), обозначающего
проведение сопоставления во время выполнения. Если включена поддержка связывания

времени выполнения, то для достижения ожидаемых результатов приведенные выше
фрагменты должны быть изменены следующим образом:

    set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "!VAR!" == "after" @echo Тело внутреннего оператора сравнения
    )

    set LIST=
    for %i in (*) do set LIST=!LIST! %i
    echo %LIST%

...
 
Автор
T

tech-gs

Знающий
Сообщения
54
Репутация
5
Morock
С параметром /V:shok:N на Win7x64 - cmd вылетает. При запуске с параметрами /K /V:shok:N читаю сообщение:
Синтаксическая ошибка в имени файла, имени папки или метке тома.
 

Yuri

AutoIT Гуру
Сообщения
737
Репутация
282
Еще можно так попробовать:
Код:
#include <Encoding.au3>

$text= "echo off" & @CRLF
$text&= _Encoding_ANSIToOEM("set VAR=Русский - Russian") & @CRLF
$text&= _Encoding_ANSIToOEM("echo Переменная VAR=%VAR%>rezult.txt") & @CRLF ;пишем в файл результат

$file = FileOpen(@ScriptDir&"\file.bat",2)
FileWriteLine($file, $text)
FileClose($file)

RunWait(@ScriptDir&"\file.bat")

$file = FileOpen(@ScriptDir&"\rezult.txt",0)
$rezult = FileReadLine($file, 1)
MsgBox(64, "Результат", _Encoding_OEM2ANSI($rezult))
FileClose($file)
 

Morock

Новичок
Сообщения
3
Репутация
1
хм
акелла промахнулся
не %VAR% а !VAR!

специально проверил на w7х64
из командной строки с ключом /v:shok:n работает

проверяй командную строку
косяк где-то там

кстати
цмд очень не нравится эхо в начале строки, лучше вместо него поставить ключик /Q
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Morock [?]
для полного понимания механики вдумчиво курим хелп
Видимо вы не внимательно читали! :smile:
Но всё же вы были на парильном пути!
Код:
RunWait('"' & @COMSPEC & '" /v:on /k "echo off && set VAR=ABC && echo VAR=!VAR! && pause && exit"')

Код:
RunWait('"' & @COMSPEC & '" /v:on /k "echo off && set VAR=ABC && echo Код возврата - VAR=!VAR! && pause && exit"')

Да, действительно, "есть такая буква в этом слове" :smile:
P.S. Нужно всё же периодически освежать память, чтением мануалов.
 
Автор
T

tech-gs

Знающий
Сообщения
54
Репутация
5
По крайней мере, этот кусок кода заработал. Ошибка была в следующем: если запускать с параметрами /V:shok:N /С - то все нормально, если их переставить местами - /С /V:shok:N - ошибка: Синтаксическая ошибка в имени файла, имени папки или метке тома.

Если получилось разобраться здесь, помогите добить еще один кусок (этот вопрос задавал чуть раньше):

Код:
RunWait('"' & @COMSPEC & '" /v:on /c "echo off && "Updater.exe" -h && set VAR=%ERRORLEVEL% && echo Код возврата - !VAR! && pause && exit /b !ERR!"')


Здесь после отработки Updater.exe (программа должна установить ERRORLEVEL=15) происходит выход из cmd (RunWait возвращает 15, как и положено), но следующие инструкции не отрабатываются. В реальной программе нужно еще кое-что выполнить после Updater.exe.
Файл Updater.exe (обновление антивирусных баз касперского) прикрепить не могу из-за ограничения в 200kb. Взять его можно здесь - http://utils.kaspersky.com/updater/updater_for_windows_v.3.5.0.34.zip
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
tech-gs [?]
Ошибка была в следующем
Выше я вам писал правильный пример ;)

Здесь после отработки Updater.exe (программа должна установить ERRORLEVEL=15) происходит выход из cmd (RunWait возвращает 15, как и положено), но следующие инструкции не отрабатываются.
Можно посмотреть весь ваш код? Или опишите что вам нужно сделать?

В реальной программе нужно еще кое-что выполнить после Updater.exe
Ну так, а что мешает?
 

Morock

Новичок
Сообщения
3
Репутация
1
tech-gs
на самом деле ошибка не в отработке, а в логике

Код:
RunWait('"' & @COMSPEC & '" /v:on /c "echo off && "Updater.exe" -h && set VAR=%ERRORLEVEL% && echo Код возврата - !VAR! && pause && exit /b !ERR!"')


конструкции && - это же не только указание следуещей команды, это еще и условие успешного завершения предыдущей
т.е. set VAR=%ERRORLEVEL% может отработать только тогда, когда этот самый эррорлевел ==0
в данном случае можно попытаться использовать конструкцию || (выполнить следующую команду, если выполнение предыдущей вернуло ошибку)

должно получиться приблизительно вот так

Код:
RunWait('"' & @COMSPEC & '" /v:on /c "echo off && "Updater.exe" -h || set VAR=%ERRORLEVEL% && echo Код возврата - !VAR! && pause && exit /b !ERR!"')


НО... цмд довольно часто путается во всяческих НЕ/И, потому условие может не срабатывать, или отрабатывать неправильно
определить будет ли работать можно только опытным путем :'(
возможно придется использовать скобки, но они тоже не всегда корректно отрабатываются :wacko:
более стабильные и предсказуемые результаты получаются если формировать временный CMD-файл, и уже его скармливать интерпретатору

собственно, я не совсем понимаю зачем эти пляски с бубном
если это все уже запускается из автоит-а
запускаем напрямую апдейтер через RunWait а потом ловим код ошибки
разве так будет не проще?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Morock [?]
set VAR=%ERRORLEVEL% может отработать только тогда, когда этот самый эррорлевел ==0
Неправда, эта команда всегда выполняется, она присваивает переменной VAR значение %ERRORLEVEL%, и не важно чему оно там равняется.

set VAR=%ERRORLEVEL% может отработать только тогда, когда этот самый эррорлевел ==0
Оно в данном случае отработает как раз тогда, когда «"Updater.exe" -h» отбработает корректно ;)

Условная обработка команд в Windows осуществляется с помощью символов && и || следующим образом. Двойной амперсанд && запускает команду, стоящую за ним в командной строке, только в том случае, если команда, стоящая перед амперсандами была выполнена успешно. Например, если в корневом каталоге диска C: есть файл plan.txt, то выполнение строки TYPE C:\plan.txt && DIR приведет к выводу на экран этого файла и содержимого текущего каталога. Если же файл C:\plan.txt не существует, то команда DIR выполняться не будет.

Два символа || осуществляют в командной строке обратное действие, т.е. запускают команду, стоящую за этими символами, только в том случае, если команда, идущая перед ними, не была успешно выполнена. Таким образом, если в предыдущем примере файл C:\plan.txt будет отсутствовать, то в результате выполнения строки TYPE C:\plan.txt || DIR на экран выведется содержимое текущего каталога.

Отметим, что условная обработка действует только на ближайшую команду, то есть в строке
TYPE C:\plan.txt && DIR & COPY /?

команда COPY /? запустится в любом случае, независимо от результата выполнения команды TYPE C:\plan.txt.

Насколько я понимаю, тут нужно делать так:
Код:
RunWait(@COMSPEC & ' /v:on /c echo off & "Updater.exe" -h & set VAR=%ERRORLEVEL% & echo Код возврата - !VAR! & pause & exit /b !VAR!')
 
Автор
T

tech-gs

Знающий
Сообщения
54
Репутация
5
CreatoR
CreatoR сказал(а):
Насколько я понимаю, тут нужно делать так:
Код: AutoIt [Выделить]
RunWait(@COMSPEC & ' /v:shok:n /c echo off & "Updater.exe" -h & set VAR=%ERRORLEVEL% & echo Код возврата - !VAR! & pause & exit /b !VAR!')

Этот код отрабатывает до конца, но ERRORLEVEL после Updater.exe все же остается равным 0, хотя точно знаю, что с ключом -h (вывод справки) должен быть ERRORLEVEL=15, с ключом -u (загрузка обновлений) при удачной загрузке - ERRORLEVEL=35. Если все это перенести в cmd-файл, то ERRORLEVEL устанавливается верно.


Garrett
Garrett сказал(а):
Можно посмотреть весь ваш код? Или опишите что вам нужно сделать?

Чтобы сильно не засорять код, лишние инструкции не привожу. Код должен выполнить подготовительные действия для выполнения обновления антивирусных баз, вывести информацию по обновляемым продуктам и т.п., обновить базы, сохранить результат выполнения Updater.exe в переменную VAR, выполнить еще пару незатейливых команд и выйти из cmd с возвратом значения VAR в переменную $ret.

Код:
$ret = RunWait(@COMSPEC & ' /v:on /c "echo off & echo Здесь несколько инструкций, подготавливающих операцию обновления баз... & "Updater.exe" -h & set VAR=%ERRORLEVEL% & echo Здесь несколько инструкций, обрабатывающих результат обновления баз... & echo Код возврата - !VAR! & pause & exit /b !VAR!"')
 

Yuri

AutoIT Гуру
Сообщения
737
Репутация
282
Этот код выдал код возврата 33 (Failed to resolve source DNS name / Не найден источник обновлений)
Специально запустил с отключенным Интернетом.
Код:
$ret = RunWait('Updater.exe -u')
MsgBox(64, "Код возврата", $ret)

С включенным долго ждать пока все базы скачаются (более 250 МБ)
Этот код выдал 15
Код:
$ret = RunWait('Updater.exe -h')
MsgBox(64, "Код возврата", $ret)
 
Верх