Пакетный досмотр повторяется через строку с разделителями - PullRequest
36 голосов
/ 26 марта 2010

У меня есть список IP-адресов с разделителями, которые я хочу обрабатывать индивидуально. Длина списка заранее неизвестна. Как разделить и обработать каждый элемент в списке?

@echo off
set servers=127.0.0.1,192.168.0.1,10.100.0.1

FOR /f "tokens=* delims=," %%a IN ("%servers%") DO call :sub %%a

:sub
    echo In subroutine
    echo %1
exit /b

Выходы:

In subroutine
127.0.0.1
In subroutine
ECHO is off.

Обновление: Используя ответ Франци в качестве ссылки, вот решение:

@echo off
set servers=127.0.0.1,192.168.0.1,10.100.0.1

call :parse "%servers%"
goto :end


:parse
setlocal
set list=%1
set list=%list:"=%
FOR /f "tokens=1* delims=," %%a IN ("%list%") DO (
  if not "%%a" == "" call :sub %%a
  if not "%%b" == "" call :parse "%%b"
)
endlocal
exit /b

:sub
setlocal
echo In subroutine
echo %1
endlocal
exit /b

:end

Выходы:

In subroutine
127.0.0.1
In subroutine
192.168.0.1
In subroutine
10.100.0.1

Ответы [ 7 ]

93 голосов
/ 11 ноября 2011

Команда for по умолчанию обрабатывает несколько разделителей. В этом случае вы можете сделать

@echo off

set servers=127.0.0.1,192.168.0.1,10.100.0.1

for %%i in (%servers%) do (
  echo %%i
)

Если вы столкнетесь с разделителем, который изначально не поддерживается, вы можете выполнить замену, чтобы сначала подготовить строку, чтобы она была в правильном формате

@echo off

set servers=127.0.0.1@192.168.0.1@10.100.0.1
set servers=%servers:@=,%

for %%i in (%servers%) do (
  echo %%i
)

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

27 голосов
/ 26 марта 2010

Обновление : Если количество элементов в списке неизвестно, все еще возможно проанализировать все элементы с помощью простой рекурсии в начале списка. (Я изменил IP-адреса на простые числа для простоты списка)

Наконец, класс Лиспа, который я посещал 18 лет назад, окупился ...

@echo off
setlocal

set servers=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24

echo %servers%

call :parse "%servers%"

goto :eos

:parse

set list=%1
set list=%list:"=%

FOR /f "tokens=1* delims=," %%a IN ("%list%") DO (
  if not "%%a" == "" call :sub %%a
  if not "%%b" == "" call :parse "%%b"
)

goto :eos

:sub

echo %1

goto :eos

:eos
endlocal
7 голосов
/ 09 марта 2012

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

rem You need to enable delayed expansion, otherwise the new line will interfere
rem with the for command.
setlocal ENABLEDELAYEDEXPANSION
rem The following three lines escape a new line and put it in a variable for
rem later.
rem The empty lines are important!
set newline=^


set list=jim alf fred
for /F %%i in ("%list: =!newline!%") do (echo item is %%i)

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

4 голосов
/ 20 января 2011

Не могу поверить, что это так сложно! Похоже, что все захотят часто разбивать строку, не зная, сколько в ней токенов, и не разбирая ее по строкам. Как правило, кажется, что люди пишут в файл, а затем переходят по нему или используют метод multi sub, как эти другие. Какой беспорядок!

Вот мое решение. За ним легче следовать, и он работает встроенным, то есть без подпрограммы. Приятно составить список имен файлов или чего-либо еще, а затем выполнить их пошагово, не записывая их во временный файл, убедиться, что нет конфликтов при записи файла, удалить временный файл и т. Д. Плюс я не знаю, как вернуть значение из подпрограммы, как будто это была функция - я не думаю, что вы можете. Таким образом, вам придется продолжать писать 2 подпрограммы с другими ответами, которые я вижу здесь каждый раз, когда вы хотите сделать что-то вроде этого - один, который подпитывает другой. Мой метод позволяет легко создавать списки и просматривать их столько раз, сколько вы хотите в течение всего сценария.

setlocal enableextensions enabledelayedexpansion

set SomeList=
set SomeList=!SomeList!a;
set SomeList=!SomeList!b;
set SomeList=!SomeList!c;
set SomeList=!SomeList!d;
set SomeList=!SomeList!e;
set SomeList=!SomeList!f;
set SomeList=!SomeList!g;

set List=!SomeList!
:ProcessList
FOR /f "tokens=1* delims=;" %%a IN ("!List!") DO ( 
  if "%%a" NEQ "" ( 
      echo %%a
  )
  if "%%b" NEQ "" (
      set List=%%b
      goto :ProcessList
  )
)

Выход:

a
b
c
d
e
f
g

Очевидно, вы можете просто обменяться эхом с чем-то полезным.

3 голосов
/ 18 августа 2011

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

:list_iter
    rem Usage: call :list_iter :do_sub_for_each_item "CSV of items"
    set foo=%1
    set list=%~2
    for /f "tokens=1* delims=," %%i in ("%list%") do (
        call %foo% %%i
        if not "%%j" == "" ( call :list_iter %foo% "%%j" )
    )
    exit /b

Например, вы можете позвонить по этому номеру:

call :list_iter :my_foo "one,two,three"
call :list_iter :my_bar "sun,poo,wee"
1 голос
/ 13 октября 2015

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

set n=1
set "server[!n!]=%servers:,=" & set /A n+=1 & set "server[!n!]=%"

Эти две строки разбивают строку servers на массив server , а также определяют переменную n с количеством созданных элементов. Таким образом, вам просто нужно использовать команду for /L от 1 до %n% для обработки всех элементов. Вот полный код:

@echo off
setlocal EnableDelayedExpansion

set servers=127.0.0.1,192.168.0.1,10.100.0.1

set n=1
set "server[!n!]=%servers:,=" & set /A n+=1 & set "server[!n!]=%"

for /L %%i in (1,1,%n%) do echo Process server: !server[%%i]!

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

Вы можете прочитать более подробную информацию о методе разделения в этот пост .

0 голосов
/ 28 декабря 2017

Если доступен PowerShell, вы можете:

C:>set servers=127.0.0.1,192.168.0.1,10.100.0.1
C:>powershell -NoProfile -Command "('%servers%').Split(',')"
127.0.0.1
192.168.0.1
10.100.0.1

Другое использование для отображения читаемой переменной PATH.

@powershell -NoProfile -Command "($Env:PATH).Split(';')"

или

powershell -NoProfile -Command "$Env:PATH -split ';'"
...