Показать полную графическую версию : [решено] Изменение глобальной переменной в дочернем процессе.
Здравствуйте.
Помогите разобраться. Есть два исполняемых фала со следующим содержимым:
xxx.cmd
echo off
SET MY_ERRORLEVEL1=1
echo xxx1 MY_ERRORLEVEL1=%MY_ERRORLEVEL1%
pause
start yyy.cmd
echo xxx2 MY_ERRORLEVEL1=%MY_ERRORLEVEL1%
pause
pause
yyy.cmd
echo off
echo yyy1 MY_ERRORLEVEL1=%MY_ERRORLEVEL1%
SET MY_ERRORLEVEL1=2
echo yyy2 MY_ERRORLEVEL1=%MY_ERRORLEVEL1%
pause
exit
Пользователь запускает файл xxx.cmd. В нем определяется переменная MY_ERRORLEVEL1. Затем из этого файла следует вызов дочернего файла yyy.cmd. При выполнении видно, что значение переменной MY_ERRORLEVEL1 в процесс yyy.cmd передается и им можно воспользоваться. Затем происходит изменение переменной MY_ERRORLEVEL1 и выход из файла. При этом новое значение переменной MY_ERRORLEVEL1 в процессе xxx.cmd (в родительском) не доступно, оно осталось старым и равно 1.
Вопрос - как в дочернем процессе изменить значение переменной, определенной в родительском процессе? Причем изменить так, чтобы новое значение было доступно в родительском процессе?
Спасибо.
P.S. общая задача такова - необходимо сделать бэкап 9 папок с разных компов. При этом, для экономии времени, копирование запускается в 9 процессов. При этом, на время выполнения дочерних процессов копирования, родительский процесс встает на паузу (ping -n 500 localhost > nul). Копирование может закончится ошибкой доступа - поэтому хочу возвращать из дочернего процесса значение переменной %ERRORLEVEL%, значение которой присвою переменным MY_ERRORLEVEL1..MY_ERRORLEVEL9
При выполнении видно, что значение переменной MY_ERRORLEVEL1 в процесс yyy.cmd передается и им можно воспользоваться. »
Не так. Создаётся копия окружения родительского процесса «cmd.exe» (в котором исполняется пакетный файл «xxx.cmd»), и порождённый процесс «cmd.exe» (в котором исполняется пакетный файл «yyy.cmd») работает именно с ней.
Затем происходит изменение переменной MY_ERRORLEVEL1 и выход из файла. При этом новое значение переменной MY_ERRORLEVEL1 в процессе xxx.cmd (в родительском) не доступно, оно осталось старым и равно 1. »
Оно и не будет доступно, поскольку изменение происходит в окружении порождённого процесса «cmd.exe», являющемся копией окружения родительского процесса «cmd.exe».
Вопрос - как в дочернем процессе изменить значение переменной, определенной в родительском процессе? Причем изменить так, чтобы новое значение было доступно в родительском процессе? »
Ответ: в рамках заданной категории и выбранного механизма исполнения — никак.
P.S. общая задача такова - необходимо сделать бэкап 9 папок с разных компов. При этом, для экономии времени, копирование запускается в 9 процессов. При этом, на время выполнения дочерних процессов копирования, родительский процесс встает на паузу (ping -n 500 localhost > nul). Копирование может закончится ошибкой доступа - поэтому хочу возвращать из дочернего процесса значение переменной %ERRORLEVEL%, значение которой присвою переменным MY_ERRORLEVEL1..MY_ERRORLEVEL9 »
Задача понятна.
Суть проблемы в том, что мы можем либо исполнять последовательно, получая результат по ErrorLevel/ExitCode дочернего процесса, либо, как у Вас, параллельно — не имея возможности получить результат исполнения по ErrorLevel/ExitCode дочернего процесса.
Я бы подумал о переходе на WSH («WshRemote»), либо PowerShell («WinRM»). Если никак — попробуйте, например, писать результат из дочерних пакетных файлов в единый текстовый файл, по строчке на машину. Родительский пакетный файл очищает/удаляет его, затем запускает по «start» N порождённых пакетных файлов отдельно. Каждый из них по исполнении дописывает свой результат в единый текстовый файл. Всё это время, родительский пакетный файл в бесконечном цикле ожидания раз, допустим, в пять секунд проверяет этот текстовый файл на предмет наличия в нём записей от всех порождённых дочерних файлов. Как только все записи окажутся в наличии — происходит выход из цикла ожидания, разбор этого текстового файла и вывод результатов.
Foreigner
09-02-2015, 21:45
Дочерний батник можно завернуть в for /f:
:: 1.cmd
@echo off
setlocal
set "var=1"
echo %var% 1.cmd
for /f %%i in ('2.cmd') do set "var=%%i"
echo %var% 1.cmd
:: 2.cmd
@echo off
setlocal
set /a var+=1
echo %var%
Foreigner, как это будет выглядеть со «start 2.cmd»?!
Iska, спасибо. Пока попробую остановиться на использовании временных файлов, создаваемых в дочерних процессах и анализируемых в родительском.
Foreigner, если я правильно понял ваш код, то выполнение файла 1.cmd остановится на время выполнения файла 2.cmd. Правильно? Меня такой вариант не устраивает - слишком долго придется ждать. И еще. Не могли бы вы объяснить 2 момента - зачем в начале используется :: и зачем нужны кавычки в строке set "var=1"? Спасибо.
upd: :: просто комментарий с именем файла?
зачем в начале используется :: »
Вместо команды комментария REM используется псевдометка.
и зачем нужны кавычки в строке set "var=1"? »
Дабы ограничить правую часть в присваивании. В данном случае нет разницы по сравнению с вариантом без кавычек.
upd: :: просто комментарий с именем файла? »
Фактически — да.
Foreigner
10-02-2015, 10:12
Меня такой вариант не устраивает - слишком долго придется ждать. »
Просто не вник в суть вопроса. Сделал акцент на возвращение переменной из дочернего батника. В любом случае можно запустить несколько копий родительского командного файла с разными аргументами (название компьютера, папки). Вопрос реализации.
Создаётся копия окружения родительского процесса «cmd.exe» »
Т.е. исходя из этого, в каждом вновь запущенном процессе будет своя переменная ERRORLEVEL со своим значением. Правильно?
Т.е. исходя из этого, в каждом вновь запущенном процессе будет своя переменная ERRORLEVEL со своим значением. »
Своя переменная окружения «MY_ERRORLEVEL1».
Iska, нет, меня интересует именно системная переменная ERRORLEVEL. Она будет своя в каждом процессе?
P.S. своя - в смысле независимая от других процессов.
Foreigner
10-02-2015, 11:47
будет своя переменная ERRORLEVEL со своим значением »
Если его определить принудительно, то нет:
@echo off
setlocal
set errorlevel=100
start /b 2.cmd
:: 2.cmd
@echo off
setlocal
echo %errorlevel%
help > nul
:: Errorlevel должен бы стать равным 1, но:
echo %errorlevel%
exit /b
Iska, нет, меня интересует именно системная переменная ERRORLEVEL. Она будет своя в каждом процессе?
P.S. своя - в смысле независимая от других процессов. »
Michael, как бы Вам сказать… Ваш вопрос лишён смысла в озвученном контексте. Такой системной переменной окружения нет.
Псевдопеременная же окружения ERRORLEVEL доступна только при включённой расширенной обработке команд (которая, впрочем, включена по умолчанию). Она вычисляется динамически, в момент раскрытия (т.е., на неё действуют все правила раскрытия обычных переменных окружения) и принимает значение кода ошибки (кода возврата), если тот был установлен одной из предыдущих внутренних или внешних команд. Если Вы принудительно определите её по «set» — получите обычную переменную окружения с тем же именем.
Правильно ли я понял, что переменную дочернего процесса не получить в родительском?
@echo off
cmd /v/c "set n=5& echo !n!& pause"
if defined n echo %n%
pause
exit
п.с. как вариант вижу решение через запись в текстовый файл и чтение из него, но может есть и иные варианты?
Правильно ли я понял, что переменную дочернего процесса не получить в родительском? »
Вы правильно поняли. Потому что родительский и дочерний процесс имеют каждый по своей независимой копии области переменных окружения.
п.с. как вариант вижу решение через запись в текстовый файл и чтение из него, но может есть и иные варианты? »
А что Вам нужно сделать? Интересует сама задача, а не выбранное Вами решение.
Задача простая - получить "рапорт" об исполнении задания дочернего процесса. Хотел через переменную, сделал через временный файл.
Под спойлером скрипт удаления не верных ярлыков. Вот только QL не смог победить ((
@Echo Off
SetLocal enabledelayedexpansion
(
echo Set oShell = CreateObject^("WScript.Shell"^)
echo Set oShortcut = oShell.CreateShortcut^(Wscript.Arguments.Item^(0^)^)
echo WScript.Echo oShortcut.TargetPath
)>$.vbs
set dir1=HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
set dir2=HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
Ver | Find "5." >Nul && call :L_XP
Ver | Find "6." >Nul && call :L_7
if exist f_lnk (echo Очистка от не верных ярлыков ^(без QL^) - OK)
if not exist f_lnk (echo Очистка от не верных ярлыков ^(без QL^) - --)
del $.vbs
del f_lnk
pause
exit
:L_XP
chcp 1251>nul
for %%a in ("%dir1%","%dir2%") do (
for /f "tokens=1-2* delims=:" %%b in ('reg query "%%~a" ^|find ":"') do (
chcp 866>nul& set r1=%%b
cmd /v /c "for %%x in ("!r1:~-1!:%%c\*.lnk") do @for /f "delims=" %%y in ('cscript //nologo "$.vbs" "%%~x"') do @if not exist "%%~y" (del /f /q "%%~x"& >f_lnk echo.1)"
))
chcp 866>nul
exit /b
:L_7
for %%a in ("%dir1%","%dir2%") do (
for /f "tokens=1-2* delims=:" %%b in ('reg query "%%~a" ^|find ":"') do (
set r1=%%b
cmd /v /c "for %%x in ("!r1:~-1!:%%c\*.lnk") do @for /f "delims=" %%y in ('cscript //nologo "$.vbs" "%%~x"') do @if not exist "%%~y" (del /f /q "%%~x"& >f_lnk echo.1)"
))
exit /b
Задача простая - получить "рапорт" об исполнении задания дочернего процесса. »
Более развёрнутый, нежели простой код возврата, так?
Вот только QL не смог победить (( »
Что такое QL?
Более развёрнутый, нежели простой код возврата, так? »
хм... интересны примеры реализации обеих вариантов. :)
Что такое QL? »
Quick Launch, панель быстрого запуска в WinXP. В Windows 7 и выше её можно добавить в панель задач. Удаление не рабочих ярлыков с панели задач и панели быстрого запуска командой del не корректно, т.к. ярлыки "привязаны" к реестру, гибрид на vbs возможно с этим мог бы помочь.
хм... интересны примеры реализации обеих вариантов. »
Первый — call в родительском, exit /b … — в дочернем, и последующий анализ errorlevel в родительском же.
Второй — например, через тот же указанный Вами вариант со временным файлом. Единственно — в родительском использовать, скажем, процедуру получения имени временного файла: CMD/BAT: генерация пути для временного файла или папки — Коллекция скриптов и идей — Серый форум (http://forum.script-coding.com/viewtopic.php?id=6259), передача этого полученного имени в дочерний через параметр, после возврата в родительский — анализ содержимого временного файла и удаление этого временного файла. Можно комбинировать с первым способом — например, можно условиться, что нулевой код возврата будет означать корректную работу дочернего пакетного файла (а разные не нулевые — ту или иную ошибку), а развёрнутые детали могут передаваться посредством временного файла.
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.