这一段倒是 不怕特殊字符。。 它是打印出每一行的字符数, 并没有进行
整体统计。。
@echo off
for /f "delims=" %%a in ('findstr /n .* test.txt') do (
set "var=%%a"
setlocal enabledelayedexpansion
set var=!var:*:=!
call :Loop
echo !n!
endlocal
)
pause
goto :eof
:Loop
if defined var (
set /a n+=1
set var=!var:~1!
goto Loop
)
当然你也可以用下面这个进行 整体统计,
但是这个对稍大点的文件就会有问题。。
导致setlocal 递归层过大。。
@echo off
for /f "delims=" %%a in ('findstr /n .* test.txt') do (
set "var=%%a"
setlocal enabledelayedexpansion
set var=!var:*:=!
call :Loop
setlocal disabledelayedexpansion
)
echo %n%
pause
goto :eof
:Loop
if defined var (
set /a n+=1
set var=!var:~1!
goto Loop
)
这里有命令行固有的缺陷
假如你想完完整整的(包括特殊字符)获取到, 那在set "var=%%a"
之前 一定不要打开 变量延迟, 不然!号和^会被吃掉。。
但这样也造成另一个问题:
假如这有最开始的一个环境变量表
|----------------------------------------------|
| |
| |
| |
-------------------------------------------------
执行set "var=%%a"后变为:
假如var=1:abcd
|----------------------------------------------|
| |
| var=1:abcd |
| |
-------------------------------------------------
当你执行 setlocal 时, 会产生一个新表, 实际上是copy调用setlocal的那张表,
但是以后对环境变量的修改只会作用于新表,当执行 endlocal 时,会恢复到原来
那张表。
执行setlocal 后产生新表
|----------------------------------------------|
| |
| var=1:abcd |
| |
-------------------------------------------------
执行
set var=!var:*:=!
call :Loop
后这张新表变为:
|----------------------------------------------|
| |
| var=abcd |
| n=4 |
-------------------------------------------------
当执行endlocal时 环境变量的表 恢复到最初 即
|----------------------------------------------|
| |
| var=1:abcd |
| |
-------------------------------------------------
可见 n 没有了。。
这也是为什么第一个代码 只统计每一行 而没有 统计全部的原因
因为每一次统计 时 执行 set /a n+=1
n的初始值都为零。
可能有人会有这样的疑问: 不执行endlocal行不行。。
答案是也行, 就比如第二段代码
但是要记住: 一定要在 set "var=%%a"之前关闭掉 变量延迟
这样会不断的递归产生 环境表。
对于小文件还尚可。。 文件行数稍大便会 导致setlocal递归层数过大
所谓cmd固有缺陷:
cmd中实际上没有真正变量的概念
而是以环境变量来模拟或者说是代替的
对于这种方式有个问题
因为 父shell 可以传递环境变量 给子shell
而 子shell 无法 改变父 shell中的环境变量
所以在setlocal后对原“变量”的修改 无法传递回来。。
除非 将其存入磁盘。。
================================
所以 更可行的方式 是 利用第一个代码, 将各行的字符数写入临时文件
最后再从 临时文件中 读取并计算和。。。
缺点自然就是 产生临时文件。
======================================
受10楼兄弟的启发, 下面这个代码即可统计 不必产生临时文件,
而且也 发现了 把变量传递回来的好办法。 很聪明的一个办法。。。
@echo off
for /f "delims=" %%a in ('findstr /n .* a.txt') do (
set "var=%%a"
call :list
)
echo.%total%
pause>nul
goto :eof
:list
setlocal enabledelayedexpansion
set /a n=0
set var=!var:*:=!
call :loop
endlocal&set /a total+=%n%
goto :eof
:loop
if defined var (
set /a n+=1
set var=!var:~1!
goto loop
)
主要在两点。。
1) 让 set /a total+=n 脱离 循环的区域 但又被执行到
原因是为了避免 在for中 没执行前的命令行扫描 即将 n 替换掉
2)endlocal&&set /a total+=n
很聪明的做法 也是传递回来的根本原因所在
因为在一行。。。 所以 命令行 会对整体进行扫描
因为扫描时还没有执行endlocal, n 的值仍然存在, 而对其的替换恰发生在此时
扫描完毕后 真正执行时,endlocal 后 还原回原来的环境变量表, 但是
set /a total+=n 在扫描后 n 被替换为一个确定的值, 因此n的值通过total
被传递回原来的环境表量表
刚好利用了 扫描替换变量和执行的时间差。。
注意一定要在同一行,
endlocal
set /a total+=n
分开写, 第二行则永远是零了。。。
Last edited by bjsh on 2008-4-26 at 11:26 AM ]