Подтвердить что ты не робот

Dos итерации через строку с разделителями

У меня есть разделенный список 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.

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

@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
4b9b3361

Ответ 1

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

Наконец, что класс Lisp, который я взял 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

Ответ 2

Команда 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 [email protected]@10.100.0.1
set servers=%servers:@=,%

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

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

Ответ 3

Трудность состоит в том, что команда 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)

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

Ответ 4

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

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

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

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

Ответ 5

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

: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"

Ответ 6

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

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

Эти две строки разбивают строку servers на server array, а также определяют переменную 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, но также позволяет напрямую использовать многосимвольную строку в качестве разделителя.

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

Ответ 7

Если 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 ';'"