中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net 论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

中国DOS联盟论坛
现在时间是 2026-06-14 18:59
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » [共同讨论]for语句读取文本内容的一些陷阱
楼 主 [共同讨论]for语句读取文本内容的一些陷阱 发表于 2007-01-25 05:33 ·  中国 广东 电信
荣誉版主
★★★★
batch fan
积分 5,226
发帖 1,737
注册 2006-03-10 00:38
UID 51697
来自 成都
状态 离线
  1、普通for语句会忽略以分号开头的文本:

  test.txt内容:

;abc
ai
::te
,te st
test

  测试代码:

@echo off
for /f "delims=" %%i in (test.txt) do echo %%i
pause

  此陷阱在不用for的 type test.txt、more test.txt和findstr .* test.txt 语句中不存在。

  2、在for语句中使用带 tokens=1* delims=: 的 findstr /n .* test.txt 的时候,会过滤掉行首的所有冒号:

  test.txt同1;
  测试代码:

@echo off
for /f "tokens=1* delims=:" %%i in ('findstr /n .* test.txt') do echo %%j
pause

  解决问题1和问题2的通用方案:

  稍微复杂一点的:

@echo off
for /f "delims=" %%i in ('findstr /n .* test.txt') do (
set "str=%%i"
call set "str=%%str:*:=%%"
call echo "%%str%%"
)
pause

  最简洁的(经测试,这个方案不具备通用性,因为"delims= eol=" 会把行首为引号的内容过滤掉,看来真是前门驱虎后门进狼、引号和分号不能兼顾啊):

@echo off
for /f "delims= eol=" %%i in (test.txt) do echo %%i
pause

  简洁方案中的"delims= eol=" 顺序不能颠倒,否则会出现偏差。

  不知道强大的 for 还会有哪些陷阱会让不明就里的我们往里跳,请各位收集一下,以便日后编写代码的时候能少走弯路。

[ Last edited by namejm on 2007-5-17 at 09:17 PM ]
本帖最近评分记录 (共 1 条) 点击查看详情
评分人分数时间
ccwan +15 2007-01-25 05:39
尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。
2 发表于 2007-01-25 05:42 ·  中国 北京 联通
银牌会员
★★★
努力做坏人
积分 1,185
发帖 438
注册 2006-08-28 12:00
UID 61449
来自 北京
状态 离线
首先我想说的是FOR语句默认是忽略以“分号”开头的行,而不是冒号。
其次for /f "eol= delims=" %%a in (xxx) do command 命令中不会忽略任何符号开头的行,也就是说会显示全部的内容........
我今后在论坛的目标就是做个超级坏人!!!
3 发表于 2007-01-25 05:46 ·  中国 广东 中山 电信
新手上路
积分 19
发帖 10
注册 2005-12-13 01:56
UID 47019
状态 离线
几乎所有教程都说delims要放在最后,今天才知道也是有陷阱的。
4 发表于 2007-01-25 05:51 ·  中国 湖南 娄底 新化县 电信
银牌会员
★★★
积分 1,218
发帖 485
注册 2006-07-21 21:24
UID 58987
来自 湖南.娄底
状态 离线
又一个值得注意的地方, 不能说是陷阱, 任何程序自然不能顾及所有方面, 这就得靠我们平时多留意了.
业精于勤而荒于嬉,形成于思而毁于随。
5 发表于 2007-01-25 05:54 ·  中国 广东 电信
荣誉版主
★★★★
batch fan
积分 5,226
发帖 1,737
注册 2006-03-10 00:38
UID 51697
来自 成都
状态 离线
Originally posted by 9527 at 2007-1-24 16:42:
首先我想说的是FOR语句默认是忽略以“分号”开头的行,而不是冒号。

  呵呵,多谢提醒,笔误已经修正。

其次for /f "eol= delims=" %%a in (xxx) do command 命令中不会忽略任何符号开头的行,也就是说会显示全部的内容........

  这个方案会忽略掉以空格打头的行,兄弟测试一下就知道了。
Originally posted by pengfei at 2007-1-24 16:51:
又一个值得注意的地方, 不能说是陷阱, 任何程序自然不能顾及所有方面, 这就得靠我们平时多留意了.

  这些值得注意的地方,在微软的使用手册里没有任何地方提及,究竟是它刻意忽略的bug还是问题太小而不屑于提及异或是没有察觉到,已经无从得知,但是从使用者的角度来说,有bug的地方却没有正式的说明,无异于是一个个隐藏着的陷阱等着别人往里跳^_^

[ Last edited by namejm on 2007-1-24 at 05:59 PM ]
尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。
6 发表于 2007-01-25 08:22 ·  中国 甘肃 平凉 电信
金牌会员
★★★★
积分 4,103
发帖 1,744
注册 2006-01-20 13:00
UID 49241
性别 男
来自 甘肃.临泽
状态 离线
"delims= eol=" 顺序不能颠倒

for /?上不是这样的啊
7 发表于 2007-01-25 08:31 ·  中国 广东 电信
荣誉版主
★★★★
batch fan
积分 5,226
发帖 1,737
注册 2006-03-10 00:38
UID 51697
来自 成都
状态 离线
  哈哈,for /? 里还说:eol=c -指一个行注释字符的结尾(就一个) 。我狂吐血ing——嘿嘿,实际上是过滤掉以 c 打头的行,不知是哪个家伙翻译的,E文也太差了点吧?

  言归正传,我所说的顺序不能颠倒,并不是指所有的情形,而是说为了能同时处理以分号和冒号打头的行内容,这个顺序不能颠倒。
尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。
8 发表于 2007-01-25 08:43 ·  中国 甘肃 平凉 电信
金牌会员
★★★★
积分 4,103
发帖 1,744
注册 2006-01-20 13:00
UID 49241
性别 男
来自 甘肃.临泽
状态 离线
Originally posted by namejm at 2007-1-25 08:31:
  哈哈,for /? 里还说:eol=c -指一个行注释字符的结尾(就一个) 。我狂吐血ing——嘿嘿,实际上是过滤掉以 c 打头的行,不知是哪个家伙翻译的,E ...

汗,才发现for /?有这么大个超级错误,狂晕中
9 发表于 2007-01-25 09:24 ·  中国 湖南 娄底 新化县 电信
银牌会员
★★★
积分 1,218
发帖 485
注册 2006-07-21 21:24
UID 58987
来自 湖南.娄底
状态 离线
for /f "eol= delims=" %%i in (test.txt) do echo %%i "eol= delims=" 不能颠倒, 本机测试没有发现错误.

看来for /?的注释真的有点问题啊.
eol=c - 指一个行注释字符的结尾(就一个)
delims=xxx - 指分隔符集。这个替换了空格和跳格键的
默认分隔符集。

上面的说明我们在理解时产生了歧义, eol是过滤与行首字符匹配的行. 就像delims默认的分隔符为空格或TAB. 而eol的默认过滤的行首字符为;号, 而for /?却没有说明.

namejm兄说明给出的解决代码, for /f "delims= eol=" %%i in (test.txt) do echo %%i 它的作用和"delims=" 一样是取消默认空格作为分隔符, 而"eol="是取消;作分隔符.

下面代码为过滤行首为冒号的行, 同时取消了默认的分号分隔符.


@echo off
for /f "delims= eol=: " %%i in (test.txt) do echo %%i
pause



test.txt

abc
:123
4:56
;
;def
::
dok:cto:::


elo分隔符只能为一个, 上面代码故意让elo有两个分隔符, 可是只过滤了行首为:号的行, 而空格行却没有过滤.
业精于勤而荒于嬉,形成于思而毁于随。
10 发表于 2007-03-14 22:30 ·  中国 江苏 南京 电信
初级用户
积分 76
发帖 39
注册 2007-03-09 06:54
UID 81169
性别 男
状态 离线
看个帖要花半个小时,,,不愧是经典帖..............................
狐狸喜欢狡猾。。
11 发表于 2007-04-04 01:07 ·  中国 浙江 杭州 电信
银牌会员
★★★
积分 1,928
发帖 931
注册 2007-01-06 11:46
UID 75624
性别 男
状态 离线
下面代码为过滤行首为冒号的行, 同时取消了默认的分号分隔符.
CODE:
--------------------------------------------------------------------------------

@echo off
for /f "delims= eol=: " %%i in (test.txt) do echo %%i
pause

应该是
下面代码为过滤行首为冒号的行, 同时取消了默认的空格和跳格键分隔符.
12 发表于 2007-05-02 15:32 ·  中国 云南 昆明 电信
初级用户
积分 57
发帖 29
注册 2006-12-27 09:36
UID 74694
性别 男
状态 离线
看来只有多多学习学习基础的东西了.看的不彻底.
13 发表于 2007-08-15 17:27 ·  中国 广东 佛山 顺德区 电信
初级用户
★★
积分 193
发帖 98
注册 2007-01-17 11:56
UID 76803
性别 男
状态 离线
。。。呵。。microsoft还有这个BUG啊。。。晕晕
这家伙很聪明 什么都没留下
14 发表于 2007-08-15 22:04 ·  中国 北京 海淀区 联通
银牌会员
★★★
积分 1,287
发帖 634
注册 2007-05-02 15:06
UID 87277
性别 男
来自 cmd.exe
状态 离线
set /?里的BUG更多。。。
15 发表于 2008-01-11 14:39 ·  中国 北京 联通
新手上路
积分 10
发帖 5
注册 2007-12-27 11:33
UID 106916
性别 男
状态 离线
恩!很多细节值得推敲
论坛跳转: