dos批处理遍历一个分隔string

我有一个我想单独处理的分隔的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. 

更新:使用Franci的答案作为参考,这里是解决scheme:

 @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 

更新 :如果列表中的项目数量未知,则仍然可以使用列表头部的简单recursion来parsing所有项目。 (为简单起见,我将IP更改为简单数字)

最后,我18年前的Lisp课程得到了回报。

 @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 

for命令默认处理多个分隔符。 在这种情况下,你可以做

 @echo off set servers=127.0.0.1,192.168.0.1,10.100.0.1 for %%i in (%servers%) do ( echo %%i ) 

如果遇到本机不支持的分隔符,可以先进行replace,以便首先准备好string,使其格式正确

 @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 ) 

使用recursion调用有一次超出列表中的特定数量的项目时可能会用尽堆栈空间。 也testing它,recursion模式似乎运行速度慢一点。

难点在于for命令是用来处理你通常在文件中find的多行文本string。 我发现这个问题的最佳解决scheme是修改您的string为多行。

 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循环将迭代空格分隔variables中的项目。 它通过用换行符replace列表variables中的空格,然后执行正常的循环。

我不敢相信这太复杂了! 似乎每个人都希望频繁地分割一个string,而不知道有多less个标记在里面,而不需要用行来parsing。 通常情况下,似乎人们正在写入一个文件,然后通过它或使用像这些其他的多子方法。 真是一团糟!

这是我的解决scheme。 这是更容易遵循和工作内联,即没有子例程。 build立一个文件名列表或任何其他的,然后通过它们,而不必写入他们的临时文件,确保没有文件写入冲突,删除临时文件等是不错的。加我不知道如何返回从一个子的价值是一个函数 – 我不认为你可以。 所以你不得不继续写下2个潜艇,并在每次你想做这样的事情时看到其他的答案 – 一个喂食另一个。 我的方法可以让您轻松创build列表,并在整个脚本中随意多次遍历它们。

 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 

显然,你可以把回声换成有用的东西。

这是Franci解决scheme的泛化,因此您可以在列表中的每个项目上执行任何作业,而不需要列表迭代代码的副本。

 :list_iter
     rem用法:call:list_iter:do_sub_for_each_item“项目的CSV”
    设置foo =%1
    设置列表=%〜2
     for / f“tokens = 1 * delims =,”%% i in(“%list%”)do(
        调用%foo%%% i
        如果不是“%% j”==“”(调用:list_iter%foo%“%% j”)
     )
    退出/ b

例如,你可以通过以下方式调用它:

调用:list_iter:my_foo“一,二,三”
电话:list_iter:my_bar“sun,poo,wee”

是的,我知道这是一个非常古老的话题,但是我最近发现了一个有趣的技巧,可以以更简单的方式执行请求的分割。 这里是:

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

这两行将serversstring拆分成server 数组,并用创build的元素数定义nvariables。 这样,您只需要使用1到%n%for /L命令来处理所有元素。 这里是完整的代码:

 @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命令的方法简单快捷,而且还允许直接使用多字符string作为分隔符。

你可以在这篇文章中阅读关于拆分方法的更多细节。