我创建了一个批处理文件,只从csv文件中提取我需要的列。最近,他们增加了16个列,它基本上破坏了我的脚本。
我的脚本如下。
@echo off
setlocal
del /f /q "output.csv"
REM The Distinguished Name of the container the new users will be placed in.
set filename="I9D14B20.csv"
for /F "skip=1 tokens=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38 delims=," %%A in (I9D14B20.csv) do (
echo %%M,%%N,%%I,%%H,%%K,%%AI>>output.csv
)
type output.csv
endlocal
pause
当它有22列时它工作正常,但现在他们又增加了一堆,我需要拔出35列(又名AI)
它"休息"在第二封信。我也试过%% 35,但它只提到第3列。
我知道这比我做的要容易,但我对.bat脚本的了解非常有限。
答案 0 :(得分:0)
for
使用字母作为变量,大写或小写变量。因此,您只能通过一个for
命令解析最多26个令牌
因此,您需要将for
循环拆分为两个:
for /F "skip=1 tokens=1-25* delims=," %%A in (I9D14B20.csv) do (
for /F "tokens=1-13 delims=," %%a in ("%%Z") do (
echo %%M,%%N,%%I,%%H,%%K,%%j>>output.csv
)
)
此处发生的是,外部for
循环将当前行拆分为26个令牌,其中%%A
最多%%Y
为列1到25,最后一个{{1}剩下的就是其余部分,因此第26,27,28列最多为38,包括分隔符;内部%%Z
循环将剩余的行(即字符串for
)再次拆分为令牌,因此令牌1为列26,令牌2为列27,依此类推。
通过这个技巧,您可以分割最多26 + 25 = 51列的行。
答案 1 :(得分:0)
首先,您不需要明确指定每个令牌。例如," delims = 1,2,3,4,5"可写成" delims = 1-5"。并且所请求的令牌不需要是连续的。例如," delims = 1,3,7,15"非常好。
其次,FOR变量总是单个字符。您不能使用%AI
等变量。
但是你有一个更重要的问题 - 单个FOR / F无法解析超过31个令牌,如https://stackoverflow.com/a/8520993/1012053所述。为了获得第35个令牌,FOR / F也必须解析所有先前的令牌,即使您没有请求所有中间值。这超过了解析的令牌的最大数量。解决方案是使用多个FOR / F语句。
另一个优化:将整个循环括在括号中并仅重定向一次更有效。代码运行得更快,您不必首先清除输出文件。
@echo off
>output.csv (
for /f "skip=1 tokens=8,9,11,13,14,30* delims=," %%A in (I9D14B20.csv) do (
for /f "tokens=5 delims=," %%H in ("%%G") do echo %%D,%%E,%%B,%%A,%%C,%%H
)
)
type output.csv
pause
另一种选择是使用我的JREPL.BAT regular expression text processing utility。 JREPL.BAT是纯脚本(混合JScript /批处理),可以在XP之后的任何Windows机器上本机运行。完整的文档嵌入在脚本中。
该解决方案使用JREPL成为单线程,并且它比任何纯批处理解决方案快得多(除了非常小的文件)。
@call jrepl "^(?:.*?,){7}(.*?),(.*?),.*?,(.*?),.*?,(.*?),(.*?),(?:.*?,){20}(.*?),.*" "$4,$5,$2,$1,$3,$6" /a /jbegln "skip=(ln==1)" /f "test.txt" /o "output.csv"