将命令的结果分配给变量(批处理文件)

时间:2015-12-30 13:27:38

标签: batch-file

我想将命令的结果存储在批处理脚本中的for循环中的变量中。我想循环遍历一系列.sql文件,计算每个文件包含的行数,并总结行数。

到目前为止,这是我的尝试:

@echo off
setlocal ENABLEDELAYEDEXPANSION

set /a count=0
set /a t=0

for /f %%a in ('dir /b *.sql') do (
    @echo %%a <- THIS PRINTS THE FILE NAME
    @set t=findstr /r /n "^" %%a | find /C ":" <- THIS IS INCORRECT
    echo %t% <- I WANT TO PRINT THE LINE COUNT FOR THE FILE
    @set /a count+=%t% <- INCREASE THE COUNTER
)
echo %count% <- PRINT TOTAL LINE COUNT

当我跑步时

findstr /r /n "^" *.sql | find /C ":"

在命令窗口中它可以工作,我知道我可以将它用于最终目标,但这个问题是关于变量赋值。 我的错误在哪里?变量t始终被赋值为0。

更新 :(仍然无效)

@echo off
setlocal ENABLEDELAYEDEXPANSION

set /a count=0
set /a t=0

for /f %%a in ('dir /b *.sql') do (
    @echo %%a
    for /L %%b in ('findstr /r /n "^" %%a ^| find /C ":"') do (
        set /a count+=%%b
    )
)
echo !count!

对于任何有兴趣在此阅读的人,这是最终的(工作版):

@ECHO off
SETLOCAL ENABLEDELAYEDEXPANSION

SET /a count=0
SET /a t=0

for /f %%a in ('dir /b *.sql') do (
    @echo %%a
    for /f %%b in ('findstr /r /n "^" %%a ^| find /C ":"') do (
        set t=%%b
    )
    ECHO !t!
    @SET /a count+=!t!
)
ECHO "Total:" !count!

2 个答案:

答案 0 :(得分:2)

@set t=findstr /r /n "^" %%a | find /C ":" <- THIS IS INCORRECT

不起作用。它将变量t设置为字符串findstr /r /n "^" %%a,并使用set过滤| find /C ":"命令的输出(不输出任何内容),其中无条件地计算零冒号。 / p>

最好的方法是:

for /f %%x in ('findstr /r /n "^" %%a ^| find /C ":"') do set t=%%x

编辑我非常专注于修复您的代码,我并没有真正意识到,您只想计算所有* .SQL文件的所有行。这很容易。无需延迟扩张:

set count=0
for /f %%a in ('type *.sql  2^>nul ^| find /n /v ""') do set /a count+=1
echo %count%

2>nul阻止type将文件名打印到屏幕上。

<强> EDIT2 我的解决方案有203个文件,总共47763行需要大约24秒。 Aschipfl的edit2解决方案大约有七个毫秒秒。令人印象深刻的...... find /c必须有一个非常有效的方法来计算线条。

我稍微更改了使用此功能的代码:

set count=0
for /f %%a in ('type *.sql  2^>nul ^| find /c /n /v ""') do set /a count+=%%a
echo %count%

还需要大约7ms。没什么大惊喜,因为它与Aschipfl的代码基本相同 - 只是格式不同。

答案 1 :(得分:2)

不需要使用findstr /N /R "^"在每行前面加上行号和:,然后计算包含:的行数。

要计算文本文件包含的行数,您只需将其重定向到find /C /V "",如下所示:

< "\path\to\file.txt" find /C /V ""

要在for循环中使用此功能,您可以执行以下操作:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

set /A COUNT=0
set /A T=0

for /F "eol=| delims=" %%A in ('dir /B "*.sql"') do (
    setlocal DisableDelayedExpansion
    echo(%%~A
    for /F %%B in ('^< "%%~A" find /C /V ""') do (
        endlocal
        set /A T=%%B
    )
    echo(!T!
    set /A COUNT+=T
)
echo Total: %COUNT%

endlocal
exit /B

切换延迟扩展是为了避免任何!文件名中的感叹号*.sql出现问题,否则会被忽略,并会出现错误消息The system cannot find the file specified.。只有(调试)行echo(!T!才需要延迟扩展;如果删除它,则可以禁用整个脚本的延迟扩展。

编辑#1:

以上是上述脚本的压缩变体,没有任何临时变量T且禁用了延迟扩展:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set /A COUNT=0

for /F "eol=| delims=" %%A in ('dir /B "*.sql"') do (
    for /F %%B in ('^< "%%~A" find /C /V ""') do (
        echo(%%~A:  %%B
        set /A COUNT+=%%B
    )
)
echo TOTAL:  %COUNT%

endlocal
exit /B

这是一个使用单个for /F循环来检索行数的脚本,这样可以find搜索*.sql文件,例如find /C /V "" "*.sql",然后例如,它的输出看起来像---------- file.sql: 5,在:之后将计数分开并总结所有这些。这种方法需要再次推迟扩展:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set /A COUNT=0

for /F "eol=| delims=" %%A in ('find /C /V "" "*.sql"') do (
    set "LINE=%%~A"
    echo(%%~A
    setlocal EnableDelayedExpansion
    set /A T=!LINE:*: =!
    for /F "delims=" %%B in ("!T!") do (endlocal & set /A COUNT+=%%B)
)
echo TOTAL:  %COUNT%

endlocal
exit /B

是的,还有第二个for /F循环嵌套,但这是将T的价值转移到endlocal障碍所必需的。

编辑#2:

这可能是确定多个文件的总行数的最佳解决方案。这允许type输出所有*.sql个文件的每一行,然后由find计算。因此for /F循环仅迭代一次,因此该脚本的整体性能非常好:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set /A COUNT=0

for /F "delims=" %%A in ('
    2^>nul type "*.sql" ^| find /C /V ""
') do (
    set /A COUNT+=%%A
)
echo TOTAL:  %COUNT%

endlocal
exit /B