简体   繁体   中英

Batch loop through file

I'm trying to make a batch process in Notepad++ that will count the number of duplicate lines from text selected.

So far I have Notepad++ working fine

NPE_CONSOLE v+
CLS
ECHO $(CURRENT_WORD)
CON_SAVETO "H:\tmp.txt"
NPE_CONSOLE v-

This scripts saves the selected text into tmp.txt with the only issue being it includes, at the bottom, CON_SAVETO "H:\\tmp.txt" but I can live with that for now.

EDIT : Also, I do not think Notepad++ is the issue here since I try running the batch file from cmd line and get the same errors/problems. I also tried setting the tmp.txt file manually and still same issues.

My batch file is what is causing issues:

::@ECHO OFF
CD "H:\"
SET counter=0
SET prev=a

FOR /F "tokens=*" %%L IN (tmp.txt) DO (
    SET blnOut=0
    SET curLine="%%L"

    IF /I %prev%==%curLine% (
        SET counter=%counter%+1
        SET blnOut=1
    )
    IF %blnOut%==0 (
        IF %prev%==a (
            SET counter=%counter%+1
            SET blnOut=1
        )
        IF %blnOut%==0 (
            ECHO %curLine%- %counter%
            SET counter=1
        )
    )
    SET prev=%curLine%
)

I've tried everything I can think of, including splitting off the process into a function, but I keep getting errors like Unexpected ) or, if it does run, it does not loop through the file.

Currently, this is tmp.txt :

1
2
3
4
5
6
7
8
1
4
5
8
4
3
4
4
5

So Ideal output is:

1 - 2
2 - 1
3 - 2
4 - 5
5 - 3
6 - 1
7 - 1
8 - 2
@ECHO OFF
SETLOCAL enabledelayedexpansion
FOR %%i IN (prev) DO SET "%%i="
FOR /f "delims=" %%i IN ('sort ^<temp.txt') DO (
 IF DEFINED prev (
  IF "!prev!"=="%%i" (SET /a count+=1) ELSE (
  ECHO !prev! - !count!
  SET "prev="
  )
 )
 IF NOT DEFINED prev (
  SET prev=%%i
  SET /a count=1
 )
)
ECHO %prev% - %count%

Here's my version. Sort the input file to group like lines together, then when the line-contents change, display the previous contents and count and reset the counter and record of previous line.

The Batch program below do what you want in a faster way, as long as the lines does not contain certain special Batch characters:

@echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%a in (tmp.txt) do (
   set /A "line[%%a]+=1"
)
for /F "tokens=2* delims=[]=" %%a in ('set line[') do (
   echo %%a - %%b
)

I have a different but easier solution for you.

You can download GNU utilities for win32 . Then just extract it. It is a collection of ported tools for Windows. Very handy.

Then use the the sort and uniq programs from there. You can find them in

extracted_folder\usr\local\wbin\

then you can just simply do

sort original_file.txt | uniq --count > count.txt

from windows command line . You will find what you need in count.txt


Make sure you have the paths correct OR you have the extracted folder in your path . If not in path then do something like

"C:\GNUWin_standalone\usr\local\wbin\sort.exe" original_file.txt | "C:\GNUWin_standalone\usr\local\wbin\uniq.exe" --count > count.txt

You can't set an environment variable and use it within the same for loop using % syntax, you need to use delayed expansion and use ! syntax.

I haven't tested this, but try this:

::@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
CD "H:\"
SET counter=0
SET prev=a

FOR /F "tokens=*" %%L IN (tmp.txt) DO (
    SET blnOut=0
    SET curLine="%%L"

    IF /I !prev!==!curLine! (
        SET counter=!counter!+1
        SET blnOut=1
    )
    IF !blnOut!==0 (
        IF !prev!==a (
            SET counter=!counter!+1
            SET blnOut=1
        )
        IF !blnOut!==0 (
            ECHO !curLine!- !counter!
            SET counter=1
        )
    )
    SET prev=!curLine!
)

Or move the body of the for loop into a subroutine.

Here's my idea for a little different direction. It outputs the results you expect. Output is not sorted; the original order of lines is maintained.

@ECHO OFF
setlocal enabledelayedexpansion

set filename=h:\tmp.txt
set idx=0

:: build array of unique lines
FOR /F "usebackq delims=" %%I IN ("%filename%") DO (

    rem :: if dupe line not already processed
    2>NUL set line | findstr /r /c:"^line\[[0-9]*\]=%%I$" >NUL || (

        rem :: add it to the array
        set "line[!idx!]=%%I"
        set /a "idx+=1"
    )
)

:: For each unique line
set /a "idx-=1"
for /L %%I in (0,1,%idx%) do (

    rem :: Echo the line contents without a line break
    set /p "=!line[%%I]! - "<NUL

    rem :: use find /c to count the instances of that line.
    findstr /b /e /c:"!line[%%I]!" "%filename%" | find /c "!line[%%I]!"
)

You made more errors, I would tell now. Look at delayed expansion , if /? , for /? , set /? and all the batch stuff ...

@ECHO OFF &setlocal enabledelayedexpansion
CD /d "H:\"
SET counter=0
SET prev=a

FOR /F "tokens=*" %%L IN (tmp.txt) DO (
    SET blnOut=0
    SET "curLine=%%L"

    IF /I "!prev!"=="!curLine!" (
        SET /a counter+=1
        SET blnOut=1
    )
    IF "!blnOut!"=="0" (
        IF "!prev!"=="a" (
            SET /a counter+=1
            SET blnOut=1
        )
        IF "!lnOut!"=="0" (
            ECHO !curLine!- !counter!
            SET counter=1
        )
    )
    SET "prev=!curLine!"
)

Your code makes no sense, if you postet the content of tmp.txt correctly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM