Управление потоком в пакетном файле

Ссылка Итерация массивов в пакетном файле

У меня есть следующее:

for /f "tokens=1" %%Q in ('query termserver') do (
    if not ERRORLEVEL (
        echo Checking %%Q
        for /f "tokens=1" %%U in ('query user %UserID% /server:%%Q') do (echo %%Q)
    )
)

При запуске query termserver из командной строки первые две строки:

Known
------------------------- 

...за которым следует список терминальных серверов. Однако я не хочу включать их в команду query user. Кроме того, есть около 4 серверов, которые я не хочу включать. Когда я передаю UserID этот код, программа сразу завершается. Я знаю, что это как-то связано с оператором if. Разве это не возможно вложить управление потоком внутри цикла for?

Я попытался установить переменную точно в имена серверов, которые я хотел проверить, но итерация закончилась на первом сервере:

set TermServers=Server1.Server2.Server3.Server7.Server8.Server10

for /f "tokens=2 delims=.=" %%Q in ('set TermServers') do (
    echo Checking %%Q
    for /f "tokens=1" %%U in ('query user %UserID% /server:%%Q') do (echo %%Q)
)

Я бы предпочел этот второй пример первому, хотя бы ради чистоты.

Любая помощь по любому из этих вопросов будет принята с благодарностью.


person IAbstract    schedule 28.04.2010    source источник


Ответы (2)


Опять же, здесь есть несколько вещей, на которые следует обратить внимание.

if errorlevel

В справке для if говорится:

IF [NOT] ERRORLEVEL number command

как синтаксис для условия if errorlevel. То есть вы должны предоставить число для сравнения. Имейте в виду, что if errorlevel n оценивается как true, если код выхода был минимум n.

So

if errorlevel 1 ...

ловит любую ошибку (о которой сигнализирует код выхода), в то время как

if errorlevel 0 ...

просто всегда верно.

В любом случае, вы, вероятно, хотите

if not errorlevel 1 ...

здесь, так как это условие истинно, если не произошло ошибки.

Пропуск строк

Команда for /f имеет аргумент skip=n, который можно использовать для пропуска строк в начале. Если ваш вывод начинается с двух строк, которые вам не нужны, вы можете просто сделать

for /f "skip=2 tokens=1" %%Q in ('query termserver') do

Перебор нескольких известных значений в for /f

Проблема с вашим вторым фрагментом кода заключается в том, что for итерирует построчно. Поэтому, когда вы даете ему единственную переменную среды, он токенизирует ее (и помещает токены в разные переменные), но цикл выполняется только один раз в строке. Также обратите внимание, что использование set здесь немного подвержено ошибкам, так как вы можете получить больше, чем хотите. Что-то типа

for /f ... in ("%TermServers%") ...

было бы проще. Тем не менее, это не решает исходную проблему. Самый простой способ решить эту проблему, вероятно, будет примерно таким:

rem space-separated list of servers
set TermServers=Server1 Server2 Server3 Server7 Server8 Server10

rem call the subroutine with the list of servers
call :query_servers %TermServers%

rem exit the batch file here, to prevent the subroutine from running again afterwards
goto :eof

rem Subroutine to iterate over the list of servers
:query_servers

  rem Process the next server in the list
  rem Note the usage of %1 here instead of a for loop variable
  echo Checking %1          
  for /f "tokens=1" %%U in ('query user %UserID% /server:%1') do (echo %%Q)

  rem Remove the first argument we just processed
  shift

  rem if there is still another server to be processed, then do so
  rem we're mis-using the subroutine label as a jump target here too
  if not [%1]==[] goto query_servers

rem This is kind of a "return" statement for subroutines
goto :eof

(не проверено, но должно работать.)

Расчетное время прибытия: Гах, и снова я упустил самый очевидный ответ:

set TermServers=Server1 Server2 Server3 Server7 Server8 Server10
for %%S in (%TermServers%) do (
    for /f "tokens=1" %%U in ('query user %UserID% /server:%1') do (echo %%Q)
)

Обратите внимание, что это просто for, не for /f, и он будет выполнять итерацию по списку значений. Я не знаю, как я пропустил это, извините.

person Joey    schedule 29.04.2010
comment
+1: еще раз ваше знание пакетных команд меня поражает, и ваши объяснения на высшем уровне - вы думали о написании справочного материала? - person IAbstract; 30.04.2010
comment
@dboarman: да; хотя я никогда не обходил его стороной. Я не такой уж и писатель (что я сейчас с болью замечаю по учебе). Кроме того, мне еще предстоит многому научиться — по крайней мере, пока я не могу воспроизвести трюки на других сайтах с пакетными файлами (хотя у меня есть свой собственный, но с меньшей практической ценностью). - person Joey; 30.04.2010
comment
@dboarman: прочитайте правку внизу. Я склонен думать слишком сложно, иногда, извините... - person Joey; 30.04.2010

Язык оболочки/пакетной обработки NT недостаточно умен, чтобы принять IF NOT ERRORLEVEL (... — вам нужно выполнить явное сравнение, например:

if not %ERRORLEVEL%==0 (
...
person ewall    schedule 28.04.2010
comment
Просто неправильно. И использование псевдопеременной %errorlevel% может быть вредным, так как она будет перекрыта, если существует переменная с таким же именем. - person Joey; 30.04.2010