0

I have been trying to create a batch file that will counts the amount of rows in several csv files and output that in a txt file. I have managed to figure out how to get the batch file to count the lines and put in a text file but I cannot find a way to get it to give the name of the file and how many lines are in the file like this..

file1.csv 100
file2.csv 112

All I manage to do is either get the rows from one file or it adds the rows from all the csv files and gives me a combined number.

This is the code I am trying to base my batch on..

@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% >>list.txt

I found it from here it's not my code How to count no of lines in text file and store the value into a variable using batch script? Then from there I have just been scouring the web for ideas

DRLINUX
  • 3
  • 1
  • 1
  • 3
  • 1
    Show us your existing code. – Magoo Dec 12 '17 at 20:41
  • @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% >>list.txt I found it from here it's not my code https://stackoverflow.com/questions/5664761/how-to-count-no-of-lines-in-text-file-and-store-the-value-into-a-variable-using Then from there I have just been scouring the web for ideas to use per csv file in the folder. The main reason is that I am using files with over a million lines and want to know before trying to use excel how many lines are there. – DRLINUX Dec 12 '17 at 20:50
  • 1
    @DRLINUX, EDIT your question with your code and remove your comment. – Squashman Dec 12 '17 at 20:55
  • It would also be helpful if you would give a brief example of the desired output. – lit Dec 12 '17 at 20:59
  • Ok code added to the main question. The desired output is also there I would like the txt file to have the name of the csv followed by the number of lines in the csv – DRLINUX Dec 12 '17 at 21:01
  • In it's simple form you could just do this: `find /C /V "" file*.csv>count.log` – Squashman Dec 12 '17 at 21:01
  • @DRLINUX, I updated my answer and also made a comment under Magoo's answer to show that his code can run faster. See the results in my updated answer as well. – Squashman Dec 13 '17 at 23:54

5 Answers5

2

In its simplest form you can use the find command to get a count of the number of lines in each file.

find /C /V "" file*.csv>count.log

That will output something like this.

---------- FILE1.CSV: 19

---------- FILE2.CSV: 28

---------- FILE3.CSV: 3

If you want to get rid of the empty lines and the leading hyphens you can run it through a FOR /F command.

@echo off
FOR /F "tokens=* delims=- " %%G IN ('find /C /V "" file*.csv') DO ECHO %%G>>count.log

Which will give you an output like this.

FILE1.CSV: 19
FILE2.CSV: 28
FILE3.CSV: 3

EDIT:

Here is a modified version of mine because you apparently didn't like the colon in the output.

set total=0
(
FOR /F "tokens=1* delims=:" %%G IN ('find /C /V "" *.csv') DO (
    FOR /F "Tokens=1* delims= " %%I IN ("%%~G") DO ECHO %%J %%H&set /a total+=%%H
)
CALL ECHO Total %%total%%
)>List.txt

Here are some timed results using Magoo's pipe logic, Magoo's using redirection logic and mine using the results straight from the find. This was tested using a 437MB file with 8,895,540 lines.

Magoo Pipe:        0 Days 0 Hours 0 Minutes And 15.19 Seconds
Magoo Redirection: 0 Days 0 Hours 0 Minutes And 5.471 Seconds
Squashman File:    0 Days 0 Hours 0 Minutes And 5.429 Seconds
Squashman
  • 13,649
  • 5
  • 27
  • 36
1
@echo off
cls
setlocal EnableDelayedExpansion
set /a total=0
(
 for %%f in (*.csv) do (
  for /f %%a in ('type "%%f"^|find /C /v  "" ') do set /a total+=%%a&echo %%f %%a
 )
 echo total !total!
)>>list.txt

GOTO :EOF

Assign each .csv filename in turn to %%f.

type that file into find and count lines. Increment the total by the count found and show the filename and individual line count (in %%a)

When done, show the total.

Redirect all output to list.txt.

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • Good Idea adding the total. One thing I have been told though is that redirection is quicker than piping the file to `FIND`. `find /C /v "" ^<"%%f"` I just got a couple of 9 Million record files from a client. I will test the theory. – Squashman Dec 12 '17 at 21:29
  • This is perfect. I have just tried it and worked very well on my files. I chose this as the answer because it is close to the code I was already working with and it gives exactly the result that was required. – DRLINUX Dec 13 '17 at 08:34
  • I tested your code on a 437MB file that had 8,895,540 lines. Piping to the find command took 14.6 seconds. Using redirection it only took 5.4 seconds. `find /C /v "" <%%f` – Squashman Dec 13 '17 at 20:23
0

This will be many times quicker on files with large number of lines.

To use cscript //nologo "C:\folder\script.vbs" c <inputfile >outputfile. c counts only. l counts and displays the lines. It uses almost no memory. It sets the environmental variable Filter_LineCount

    If LCase(Arg(0)) = "l" then
        Do Until Inp.AtEndOfStream
            Line=Inp.readline
            Count = Count +1
            outp.writeline Line
        Loop
    ElseIf LCase(Arg(0)) = "c" then
        Do Until Inp.AtEndOfStream
            Line=Inp.readline
            Count = Count +1
        Loop
        outp.writeline Count
    End If

    'Create a batchfile that filter.bat will run as last step to set the environmental variable %Filter_LineCount%.
    On Error Resume Next
    Set Fso = CreateObject("Scripting.FileSystemObject")
    Set File = Fso.CreateTextFile("%temp%\FilterExit.bat", True)
    If err.number <> 0 then
        Outp.WriteLine "Error: " & err.number & " " & err.description & " from " & err.source
        err.clear
        wscript.exit
    End If
    File.WriteLine "set Filter_LineCount=" & Count
    File.close

And in the batch file that calls it put these lines last

If exist "%Temp%\FilterExit.bat" call "%Temp%\FilterExit.bat"
If exist "%temp%\FilterExit.bat" del "%Temp%\FilterExit.bat"

LineCount

filter lc {c|l} filter linecount {c|l}

Counts the lines in a file. Prints either the count or the lines to StdOut and sets the environmental variable Filter_LineCount to the count.

l - prints the lines and sets the environmental variable Filter_LineCount to the count.
c - prints the count and sets the environmental variable Filter_LineCount to the count.

Example

filter lc c < "%systemroot%\win.ini"
ACatInLove
  • 530
  • 2
  • 5
0

I like Squashman's approach, but it would fail in a rare case when a file name begins with a hyphen -. Also find converts all file names to upper-case.

If you want the original file names and you have file names that begin with -, you could use this:

@echo off
> "count.log" (
    for %%F in ("file*.csv") do (
        for /F %%E in ('^< "%%~F" find /C /V ""') do (
            echo(%%~F: %%E
        )
    )
)

This uses input redirection < for the find command, so it returns the pure number of lines of lines without any prefix.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
0

A PowerShell way would be:

Get-ChildItem -File *.csv |
    ForEach-Object {[string]::Format('{0} {1}', $_.name, (Get-Content $_.FullName).Length)} |
    Out-File -FilePath countls2.txt -Encoding ASCII

Using aliases which should not be put into .ps1 files:

gci *.csv|%{[string]::Format('{0}: {1}',$_.name,(gc $_.FullName).Length)}|Out-File countls2.txt ASCII

I predict that you will want to quote the file names or use a delimiter before the count. That would be useful if a filename ever had a SPACE character in it.

lit
  • 14,456
  • 10
  • 65
  • 119