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!]=%"
这两行将servers
string拆分成server
数组,并用创build的元素数定义n
variables。 这样,您只需要使用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作为分隔符。
你可以在这篇文章中阅读关于拆分方法的更多细节。