bja*_*jax 36 command-line batch-file
我有一个我想单独处理的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
Run Code Online (Sandbox Code Playgroud)
输出:
In subroutine
127.0.0.1
In subroutine
ECHO is off.
Run Code Online (Sandbox Code Playgroud)
更新: 使用Franci的答案作为参考,这是解决方案:
@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
Run Code Online (Sandbox Code Playgroud)
输出:
In subroutine
127.0.0.1
In subroutine
192.168.0.1
In subroutine
10.100.0.1
Run Code Online (Sandbox Code Playgroud)
Mat*_*ict 94
for命令默认处理多个分隔符.在这种情况下,你可以做到
@echo off
set servers=127.0.0.1,192.168.0.1,10.100.0.1
for %%i in (%servers%) do (
echo %%i
)
Run Code Online (Sandbox Code Playgroud)
如果您遇到本机支持的分隔符,您可以执行替换以首先准备字符串,使其格式正确
@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
)
Run Code Online (Sandbox Code Playgroud)
一旦遍历列表中的特定数量的项目,使用递归调用就有可能耗尽堆栈空间.同样测试它,递归模式似乎运行得慢一点.
Fra*_*nov 28
更新:如果列表中的项目数目未知,则仍可以使用列表头部的简单递归来解析所有项目.(为了简化列表,我已将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
Run Code Online (Sandbox Code Playgroud)
小智 7
我不敢相信这这么复杂!似乎每个人都想频繁地分割一个字符串,而不知道其中有多少个标记,也不按行解析它。通常,人们似乎正在写入文件,然后单步执行它或使用像其他方法一样的多子方法。真是一团糟!
这是我的解决方案。它更容易遵循并且内联工作,即没有子例程。建立一个文件名列表或其他内容,然后逐步浏览它们,而不必将它们写入临时文件,确保没有文件写入冲突,删除临时文件等,这很好。另外,我不知道如何返回来自 sub 的值就像它是一个函数一样 - 我认为你不能。因此,每次你想做这样的事情时,你都必须继续写 2 个 subs 以及我在这里看到的其他答案 - 一个提供另一个答案。我的方法可以让您轻松创建列表,并在整个脚本中根据需要多次单步执行它们。
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
)
)
Run Code Online (Sandbox Code Playgroud)
输出:
a
b
c
d
e
f
g
Run Code Online (Sandbox Code Playgroud)
显然你可以用有用的东西来交换回声。
困难在于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)
Run Code Online (Sandbox Code Playgroud)
最后一个for循环将迭代空格分隔变量中的项.它通过用换行符替换列表变量中的空格,然后执行正常的循环来完成它.
是的,我知道这是一个非常古老的主题,但我最近发现了一个有趣的技巧,可以以更简单的方式执行请求的拆分。这里是:
set n=1
set "server[!n!]=%servers:,=" & set /A n+=1 & set "server[!n!]=%"
Run Code Online (Sandbox Code Playgroud)
这两行将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]!
Run Code Online (Sandbox Code Playgroud)
这种方法不仅比任何其他基于for命令的方法更简单、更快,而且还允许直接使用多字符字符串作为分隔符。
您可以在这篇文章中阅读有关拆分方法的更多详细信息。