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

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

  1. Введите имя пользователя
  2. Итерация терминальных серверов
  3. Отображение серверов, на которых находится пользователь (они могут быть найдены на нескольких серверах время от времени в зависимости от того, как теряется соединение)
  4. Показать меню опций

Итерация терминальных серверов у меня есть:

for /f "tokens=1" %%Q in ('query termserver') do (set __TermServers.%%Q)

Теперь я получаю ошибку...

Environment variable __TermServers.SERVER1 not defined

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

Я также думаю, что для продолжения работы над итерацией (каждый терминальный сервер) мне нужно будет сделать что-то вроде:

:Search    
for /f "tokens=1" %%Q in ('query termserver') do (call Process) 
goto Break

:Process
for /f "tokens=1" %%U in ('query user %%username%% /server:%%Q') do (set __UserConnection = %%C)
goto Search

Тем не менее, есть 2 вещи, которые меня беспокоят в этом:

  1. Значение %%Q все еще активно при вызове Process?
  2. Когда я перейду к поиску, будет ли цикл for начинаться заново?

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

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


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


Ответы (1)


Хорошо, это довольно много вопросов/проблем/и т.д. в одной :-)

И я до сих пор не совсем понимаю, куда именно вы клоните с этим сценарием.

Во-первых, синтаксис команды set таков:

set <variable name>=<value>

Если вы сделаете просто

set <variable name>

затем он перечислит все переменные среды, начиная с <variable name>. Если их нет, то будет выведено сообщение об ошибке, которое вы видите.

Если вы хотите определить переменную, не заботясь о ее значении, вам все равно нужно предоставить значение. Я обычно использую 1 для таких флагов, так как это скорее переключатель включения/выключения, чем фактическая переменная, содержащая значение:

set Foo=1

Однако в вашем случае вы, вероятно, хотите что-то еще. В пакетных файлах нет массивов как таковых, вы можете имитировать их, создав ряд переменных и где-то удерживая счетчик. Я уже писал об этом однажды (немного устарел, но все еще актуален). ).

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

for /f "tokens=1" %%Q in ('query termserver') do (
   for /f "tokens=1" %%U in ('query user ... /server:%%Q' do (
      ...
   )
)

Что касается ваших двух вопросов:

  1. Нет, переменная цикла допустима только внутри цикла, а не при вызове подпрограммы. Однако вы можете передать его подпрограмме:

    for ... in (...) do call Process %%Q
    

    Затем вы можете получить к нему доступ с помощью %1 в подпрограмме. Честно говоря, в большинстве случаев я думаю, что вложенные циклы легче читать.

  2. Да.

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

set variable=value

Обратите внимание, что вокруг знака = нет пробела. Если есть, то у вас есть пробел в конце имени переменной или в начале значения:

> set foo = bar
> echo %foo%
%foo%
> echo %foo %
 bar
person Joey    schedule 27.04.2010
comment
+1 и проверьте: отличные описания и пояснения. Если бы я мог проголосовать несколько раз, я бы это сделал. Мне еще предстоит найти превосходный ресурс в Интернете, который дает хорошую информацию и полные примеры. В очередной раз отлично!!! - person IAbstract; 28.04.2010