62

I want to count the no of lines in a text file and then the value has to be stored into a environment variable. The command to count the no of lines is

findstr /R /N "^" file.txt | find /C ":"

I refered the question How to store the result of a command expression in a variable using bat scripts? Then I tried,

set cmd="findstr /R /N "^" file.txt | find /C ":" "

I am getting the error message,

FIND: Parameter format not correct

How could i get rid of this error.

0

17 Answers 17

107

There is a much simpler way than all of these other methods.

find /v /c "" filename.ext

Holdover from the legacy MS-DOS days, apparently. More info here: https://devblogs.microsoft.com/oldnewthing/20110825-00/?p=9803

Example use:

adb shell pm list packages | find /v /c ""

If your android device is connected to your PC and you have the android SDK on your path, this prints out the number of apps installed on your device.

Sign up to request clarification or add additional context in comments.

8 Comments

that doesn't meet the requirement to store the value in an environment variable.
clean and quite efficient. nice.
@ChrisJJ if you set up a subroutine (or .bat) that just does :SET __ for /f "tokens=*" %%A in ('%2 %3 %4 %5 %6 %7 %8 %9') do Set "%1=%%A" __ Exit \B you can save any one-line-output program to a var just by calling it like so; Call :SET varName find /v /c "" filename.ext (where __ is a newline)
I don't know why this answer has so many upvotes. The earlier responses included the same find command but also provided the count in a variable as requested.
To get the result in variable LINE, use for /F "usebackq tokens=3 delims=:" %%L in (`find /v /c "" %logfile%`) do set lines=%%L
|
41

You could use the FOR /F loop, to assign the output to a variable.

I use the cmd-variable, so it's not neccessary to escape the pipe or other characters in the cmd-string, as the delayed expansion passes the string "unchanged" to the FOR-Loop.

@echo off
cls
setlocal EnableDelayedExpansion
set "cmd=findstr /R /N "^^" file.txt | find /C ":""

for /f %%a in ('!cmd!') do set number=%%a
echo %number%

2 Comments

Thanks a ton for this, I used it in "questions/1350225" and it worked perfectly!
Thanks a lot! I just tried it here to count the lines on ALL files within a directory and it worked fine too. Just replace file.txt to *.txt and wait. :)
16

Inspired by the previous posts, a shorter way of doing so:

CMD.exe
C:\>FINDSTR /R /N "^.*$" file.txt | FIND /C ":"

The number of lines

Try it. It works in my console.

EDITED:

(the "$" sign removed)

FINDSTR /R /N "^.*" file.txt | FIND /C ":"

$ reduces the number by 1 because it is accepting the first row as Field name and then counting the number of rows.

2 Comments

this gives a lot of errors if the file has very lone lines, however the final output is still correct
The question already has these commands, but asks how to store the value into a variable and fix an error while doing so.
12

Try this:

@Echo off
Set _File=file.txt
Set /a _Lines=0
For /f %%j in ('Find "" /v /c ^< %_File%') Do Set /a _Lines=%%j
Echo %_File% has %_Lines% lines.

It eliminates the extra FindStr and doesn't need expansion.


- edited to use ChrisJJ's redirect suggestion. Removal of the TYPE command makes it three times faster.

2 Comments

Thanks. That gets my vote :) . But I find the type command is not needed. For /f %%j in ('Find "" /v /c ^< %_File%') Do Set /a _Lines=%%j
Hi ChrisJJ, your usage of the < and my TYPE | equate to the same thing.
5
for /f "usebackq" %A in (`TYPE c:\temp\file.txt ^| find /v /c "" `) do set numlines=%A

in a batch file, use %%A instead of %A

Comments

4

@Tony: You can even get rid of the type %file% command.

for /f "tokens=2 delims=:" %%a in ('find /c /v "" %_file%') do set /a _Lines=%%a

For long files this should be even quicker.

2 Comments

This is faster, but with this approach, if the file name contains a colon (for instance, "c:\temp\file.txt"), it's parsing that string at the colon instead of the result of the command.
for %%a in ("%file%") do for /f "tokens=3 delims=:" %%b in ('find /v /c "" "%%~fa"') do set lines=%%b handles short and long file names.
4

I usually use something more like this for /f %%a in (%_file%) do (set /a Lines+=1)

1 Comment

slow for large files and doesn't count empty lines (they are ignored by for /f so the counter doesn't increase)
4

The perfect solution is:

FOR /F %%i IN ('TYPE "Text file.txt" ^| FIND /C /V ""') DO SET Lines=%%i

6 Comments

It's a good solution, but the same answer was given already many times for this question. The oldest, equal answer is from 2012
but the more simply and logic.
@jeb, please show us the duplicate. I don't see any in the same context. You actions baffle me.
Tunde-Pizzle: The duplicate is this part, already given in @jeb's answer: for /f %%a in ('!cmd!') do set number=%%a
@TundePizzle My answer from 2012-02-27 is a match, and jeb's answer from 2011-04-14 is very similar. Why are you baffled?
|
2

I found this solution to work best for creating a log file that maintains itself:

setlocal enabledelayedexpansion
SET /A maxlines= 10
set "cmd=findstr /R /N "^^" "filename.txt" | find /C ":""
 for /f %%a in ('!cmd!') do set linecount=%%a
GOTO NEXT

:NEXT 
 FOR /F %%A IN ("filename.txt") DO ( 
  IF %linecount% GEQ %maxlines% GOTO ExitLoop
  echo %clientname% %Date% %Time% >> "filename.txt")
 EXIT

:ExitLoop
 echo %clientname% %Date% %Time% > "filename.txt"
 EXIT

Environmental variables included are %clientname% the computername of the remote client %Date% is the current date and %Time% the current time. :NEXT is called after getting the number of lines in the file. If the file line count is greater than the %maxlines% variable it goes to the :EXITLOOP where it overwrites the file, creating a new one with the first line of information. if it is less than the %maxlines% variable it simply adds the line to the current file.

Comments

2

The :countLines subroutine below accepts two parameters: a variable name; and a filename. The number of lines in the file are counted, the result is stored in the variable, and the result is passed back to the main program.

The code has the following features:

  • Reads files with Windows or Unix line endings.
  • Handles Unicode as well as ANSI/ASCII text files.
  • Copes with extremely long lines.
  • Isn’t fazed by the null character.
  • Raises an error on reading an empty file.
  • Counts beyond the Batch max int limit of (31^2)-1.
@echo off & setLocal enableExtensions disableDelayedExpansion

call :countLines noOfLines "%~1" || (
    >&2 echo(file "%~nx1" is empty & goto end
) %= cond exec =%
echo(file "%~nx1" has %noOfLines% line(s)

:end - exit program with appropriate errorLevel
endLocal & goto :EOF

:countLines result= "%file%"
:: counts the number of lines in a file
setLocal disableDelayedExpansion
(set "lc=0" & call)

for /f "delims=:" %%N in ('
    cmd /d /a /c type "%~2" ^^^& ^<nul set /p "=#" ^| (^
    2^>nul findStr /n "^" ^&^& echo(^) ^| ^
    findStr /blv 1: ^| 2^>nul findStr /lnxc:" "
') do (set "lc=%%N" & call;) %= for /f =%

endlocal & set "%1=%lc%"
exit /b %errorLevel% %= countLines =%

I know it looks hideous, but it covers most edge-cases and is surprisingly fast.

1 Comment

An underrated answer,i comparted it with other batch files and used them on a files containing millions of passwords and to my surprise this babe here gave me answer in approx 5-6 seconds and other batch files gave me the answer in at least 15 to 20 seconds.a vote up from me
2

You don't need to use find.

@echo off
set /a counter=0
for /f %%a in (filename) do set /a counter+=1
echo Number of lines: %counter%

This iterates all lines in the file and increases the counter variable by 1 for each line.

2 Comments

But it doesn't count empty lines and lines starting with semi colon
and it's slow. find /c /v "" is very efficient.
1

Just:

c:\>(for /r %f in (*.java) do @type %f ) | find /c /v ""

Font: https://superuser.com/questions/959036/what-is-the-windows-equivalent-of-wc-l

Comments

0

In the below code, the variable name are SalaryCount and TaxCount

@ECHO OFF    
echo Process started, please wait...    
for /f %%C in ('Find /V /C "" ^< "D:\Trial\Salary.txt"') do set SalaryCount=%%C    
echo Salary,%SalaryCount%
for /f %%C in ('Find /V /C "" ^< "D:\Trial\Tax.txt"') do set TaxCount=%%C
echo Tax,%TaxCount%

Now if you need to output these values to a csv file, you could use the below code.

@ECHO OFF
cd "D:\CSVOutputPath\"
echo Process started, please wait...
echo FILENAME,FILECOUNT> SUMMARY.csv
for /f %%C in ('Find /V /C "" ^< "D:\Trial\Salary.txt"') do set Count=%%C
echo Salary,%Count%>> SUMMARY.csv
for /f %%C in ('Find /V /C "" ^< "D:\Trial\Tax.txt"') do set Count=%%C
echo Tax,%Count%>> SUMMARY.csv

The > will overwrite the existing content of the file and the >> will append the new data to existing data. The CSV will be generated in D:\CSVOutputPath

Comments

0

You can pipe the output of type into find inside the in(…) clause of a for /f loop:

for /f %%A in ('
    type "%~dpf1" ^| find /c /v ""
') do set "lineCount=%%A"

But the pipe starts a subshell, which slows things down.

Or, you could redirect input from the file into find like so:

for /f %%A in ('
    find /c /v "" ^< "%~dpf1"
') do set "lineCount=%%A"

But this approach will give you an answer 1 less than the actual number of lines if the file ends with one or more blank lines, as teased out by the late foxidrive in counting lines in a file.

And then again, you could always try:

find /c /v "" example.txt

The trouble is, the output from the above command looks like this:

---------- EXAMPLE.TXT: 511

You could split the string on the colon to get the count, but there might be more than one colon if the filename had a full path.

Here’s my take on that problem:

for /f "delims=" %%A in ('
    find /c /v "" "%~1"
') do for %%B in (%%A) do set "lineCount=%%B"

This will always store the count in the variable.

Just one last little problem… find treats null characters as newlines. So if sneaky nulls crept into your text file, or if you want to count the lines in a Unicode file, this answer isn’t for you.

1 Comment

Most of this info already exists in previous answers or comments, your solution basically splits the output by a space, like in this comment. The only unique info is about "1 less" and the nulls. In fact, using the find command in any way will return the count - 1 if the last line is blank. ;-)
0

One nice surprise is for one who has git bash on his windows: just plain old linux wc -l <filename> will works for you there

Comments

0

You can also try

set n=0 & for /f "tokens=*" %a in (text.txt) do set/a n=!n!+1
echo !n!

1 Comment

a) doesn't count empty lines b) is incredibly slow c) there are several identical or very similar answers many years old.
-2

You can also mark with a wildcard symbol * to facilitate group files to count.

Z:\SQLData>find /c /v "" FR_OP133_OCCURENCES_COUNT_PER_DOCUMENTS_*.txt

Result

---------- FR_OP133_OCCURENCES_COUNT_PER_DOCUMENTS_AVIFRS01_V1.TXT: 2041

---------- FR_OP133_OCCURENCES_COUNT_PER_DOCUMENTS_AVIOST00_V1.TXT: 315938

---------- FR_OP133_OCCURENCES_COUNT_PER_DOCUMENTS_AVIFRS00_V1.TXT: 0

---------- FR_OP133_OCCURENCES_COUNT_PER_DOCUMENTS_CNTPTF00_V1.TXT: 277

3 Comments

You answered some other question, the current question is how to store the result into a variable
Well this was to expand the answers already presented. Plus your answer is the least efficient.
You should use comments or the Edit link for this as was already done in this comment. And the least efficient is probably this one.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.