Count number of | - batch-file

I need help with a script, the script is supposed to count the number of | before a specific string.
info.txt
text=jam|hello=123|result=ok|cow=cat|...
So in this example the answer should be 2 if you search for result=
Is this possible in batch?

try this:
#ECHO OFF &SETLOCAL
SET "string=text=jam|hello=123|result=ok|cow=cat|..."
SET "stop=result=ok"
SET "char=|"
SET /a count=-1
SET "org=%string%"
:loop
FOR /f "tokens=1*delims=%char%" %%a IN ("%string%") DO SET "this=%%a"&SET "that=%%b"
IF DEFINED that (SET "string=%that%") ELSE (SET "string=%this%")
SET /a count+=1
IF NOT DEFINED string (ECHO NOT found: "%stop%" &GOTO :EOF)
IF NOT "%this%"=="%stop%" GOTO :loop
ECHO Number of "%char%" IN "%org%" until "%stop%": %count%

This uses a helper batch file called repl.bat: from - http://www.dostips.com/forum/viewtopic.php?f=3&t=3855
If you call this code below searchstring.bat then you can launch it like this
searchstring "result="
It expects only one match per file and is case sensitive.
#echo off
type "file.txt" | find "%~1" | repl "(.*).%~1.*" "$1" | repl "\x7c" "\r\n" x | find /c /v ""
This batch file below will return a count of line number and the number itself, when the number is greater than zero, per each line in the file.txt
#echo off
if "%~1"=="" ( echo add a search term&pause&goto :EOF)
for /f "tokens=1,* delims=:" %%a in ('findstr /n "^" "file.txt" ') do (
for /f %%c in (' echo "%%b"^| find "%~1" ^| repl "(.*).%~1.*" "$1" ^| repl "\|" "\r\n" x ^| find /c /v "" ') do (
if %%c GTR 0 echo Line %%a: %%c
)
)
pause

If you want, eg, 3rd string:
SET "text=jam|hello=123|result=ok|cow=cat|..."
FOR /F "TOKENS=3" %%t IN ("%text%") DO ECHO %%t
If you want, eg, 3rd string and following:
SET "text=jam|hello=123|result=ok|cow=cat|..."
FOR /F "TOKENS=2,*" %%t IN ("%text%") DO ECHO %%u

Here's another way (uses your info.txt file).
Case insensitive. Handles multiple lines with matching string in file.
#echo off
set "SpecificString=result=ok"
set /A cnt=0
for /F "tokens=*" %%A IN (info.txt) do (
for /F "usebackq tokens=*" %%B IN (`echo."%%A" ^| find /I "%SpecificString%"`) do (
call :Parse "%%~A"
)
)
pause
goto :eof
:Parse
for /F "usebackq tokens=1* delims=^|" %%B IN (`echo."%~1"`) do (
if /I "%%~B"=="%SpecificString%" (
echo.Cnt=%Cnt% in "%%A"
echo.
set /A Cnt=0
goto :eof
)
set /A Cnt+=1
call :Parse "%%~C
)
goto :eof

Related

Add numbers with same text together

I would like to create a batch file in which I can see what I have collected in a game.
The game saves this information in a .txt file.
The output would look like this.
70x Silver.
Back Pearl.
41x Copper.
Amethyst.
Amethyst.
12x Silver.
Back Pearl.
21x Copper.
5x Silver.
Back Pearl.
Back Pearl.
Amethyst.
What I want to do now, is to add the items with the same name together, like this:
128x Silver.
4x Back Pearl.
62x Copper.
3x Amethyst.
There are hundreds of items with different names, not just these 4.
Would that be possible?
Any help would be appreciated. Thanks!
Another one!
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%l in (test.txt) do for /F "tokens=1*" %%a in ("%%l") do (
set "first=%%a"
if "!first:~-1!" equ "x" (set /A "num=!first:~0,-1!") else set "num=0"
if !num! equ 0 (
set "rest=%%l"
set /A "count[!rest: =_!]+=1"
) else (
set "rest=%%b"
set /A "count[!rest: =_!]+=num"
)
)
(for /F "tokens=2* delims=[]=" %%a in ('set count[') do (
set "item=%%a"
if %%b equ 1 (
echo !item:_= !
) else (
echo %%bx !item:_= !
)
)) > summary.txt
#ECHO OFF
SETLOCAL
rem The following settings for the source directory and filename are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "filename1=%sourcedir%\q72672485.txt"
:: remove variables starting #
FOR /F "delims==" %%b In ('set # 2^>Nul') DO SET "%%b="
FOR /f "usebackqdelims=" %%b IN ("%filename1%") DO (
CALL :sub %%b
)
SETLOCAL ENABLEDELAYEDEXPANSION
(
FOR /F "tokens=1,2delims==" %%b In ('set # 2^>Nul') DO (
SET "line=%%cx%%b"
ECHO !line:#= !
)
)>summary.txt
endlocal
type summary.txt
GOTO :EOF
:sub
SET "quantity=%1"
SET "line=%*"
IF /i "%quantity:~-1%"=="x" (SET /a quantity=%quantity:~0,-1%&SET "line=%line:* =%") ELSE SET quantity=1
IF %quantity%==0 SET /a quantity=1&SET "line=%*"
SET /a #%line: =#%+=quantity
GOTO :eof
Different approach...
Would that be possible? - Yes.
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in (t.txt) do (
set " z=%%a"
set " z=!z:x =#!"
set " z=!z: =_!"
for /f "tokens=1,2 delims=#" %%b in ("!z!") do (
if "%%c" == "" (
set "x=1"
set "y=%%b
) else (
set "x=%%b"
set "y=%%c"
)
set /a #!y!+=!x!
)
)
(for /f "tokens=1,2 delims=#=" %%a in ('set #') do (
set "x=%%a"
set "y=%%bx "
echo !y:~0,4! !x:_= !
))>summary.txt
Output with your example data (I hope, alphabetic sorting is ok for you):
3x Amethyst.
4x Back Pearl.
62x Copper.
87x Silver.
(your calculation of 120 silver might be a bit optimistic with the given input data)
This is a different approach that use a "file merge" method. The overall code is somewhat simpler than other methods...
#echo off
setlocal EnableDelayedExpansion
set "lineNum=0"
(for /F "tokens=1,2* delims=:x " %%a in ('(type test.txt ^& echo 0x^) ^| findstr /N "[0-9][0-9]*x"') do (
if !lineNum! lss %%a call :locateLine %%a
set "line=%%c"
set /A "count[!line: =_!]+=%%b"
)) < test.txt
set "count[="
(for /F "tokens=2* delims=[]=" %%a in ('set count[') do (
set "item=%%a"
if %%b equ 1 (echo !item:_= !) else echo %%bx !item:_= !
)) > summary.txt
goto :EOF
:locateLine num
set /A "lineNum+=1" & set /P "line=" & if errorlevel 1 exit /B
if %lineNum% lss %1 set /A "count[%line: =_%]+=1" & goto locateLine
exit /B
Another approach (splitting the file into items with and without quantity) (also fixing the Pollux Infusion issue in my first answer):
#echo off
setlocal enabledelayedexpansion
REM process lines without quantity:
for /f "delims=" %%a in ('type test.txt^|findstr /vrc:"[0123456789][0123456789]*x "') do call :count 1 "%%a"
REM process lines with quantity:
for /f "tokens=1*delims=x " %%a in ('type test.txt^|findstr /rc:"[0123456789][0123456789]*x "') do call :count %%a "%%b"
REM reformat:
(for /f "tokens=1,2 delims=#=" %%a in ('set #') do (
set "count=%%bx "
set "line=!count:~0,5!%%a" &REM including '1x'
if %%b==1 set "line= %%a" &REM supressing '1x'
echo !line:_= !
))>summary.txt
type summary.txt
goto :eof
:count
set item=%~2
set "item=%item: =_%"
set /a #%item% +=%1
Included both with and without 1x. Remove the line, you don't want.

Scheduled batch file error (0xff) - Executing normal it work fine

I've this batch file to execute.
#echo off
set /a count=0
for /f "tokens=1delims=:" %%i in ('findstr /n "^" "foto1.txt"') do set /a count=%%i
set /a rd=%random%%%count
if %rd% equ 0 (set "skip=") else set "skip=skip=%rd%"
set "found="
for /f "%skip%tokens=1*delims=:" %%i in ('findstr /n "^" "foto1.txt"') do if not defined found set "found=%%i"&set "var=%%j"
echo.%var%
break > urlfoto1.txt
echo %var% >> urlfoto1.txt
set /a count=0
for /f "tokens=1delims=:" %%i in ('findstr /n "^" "foto2.txt"') do set /a count=%%i
set /a rd=%random%%%count
if %rd% equ 0 (set "skip=") else set "skip=skip=%rd%"
set "found="
for /f "%skip%tokens=1*delims=:" %%i in ('findstr /n "^" "foto2.txt"') do if not defined found set "found=%%i"&set "var=%%j"
echo.%var%
break > urlfoto2.txt
echo %var% >> urlfoto2.txt
set /a count=0
for /f "tokens=1delims=:" %%i in ('findstr /n "^" "foto3.txt"') do set /a count=%%i
set /a rd=%random%%%count
if %rd% equ 0 (set "skip=") else set "skip=skip=%rd%"
set "found="
for /f "%skip%tokens=1*delims=:" %%i in ('findstr /n "^" "foto3.txt"') do if not defined found set "found=%%i"&set "var=%%j"
echo.%var%
break > urlfoto3.txt
echo %var% >> urlfoto3.txt
This script is generating random jpg url from a list on a file and create a txt new file with 1 random jpg url.
When I exectute it manually, it work fine.
But when I go to scheduling it with Windows Task Scheduler I retrieve a (0xFF) ERROR.
What does (0xff) mean? And why the scheduling is not working?
And similarly to LotPings answer:
#Echo Off
CD /D "%~dp0"
For %%A In (1 2 3) Do Call :Sub "%%A"
Pause
GoTo :EOF
:Sub
For /F "Delims==" %%A In ('Set line[ 2^>Nul') Do Set "%%A="
Set "total="&Set "randlinenum="
For /F "Tokens=1*Delims=[]" %%A In ('Find /V /N ""^<"foto%~1.txt"'
)Do Set "line[%%A]=%%B"&Set "total=%%A"
Set /A randlinenum=1+(%RANDOM% %% total)
SetLocal EnableDelayedExpansion
Echo(!line[%randlinenum%]!
(Echo(!line[%randlinenum%]!)>"urlfoto%~1.txt"
EndLocal
Exit /B
Please note that the Find /V /N "", (or FindStr /N "^"), construct will also include any empty lines, so if those exist in any of your foto* files this could feasibly randomly select and output an empty line.
I don't like the redundancy in your batch, use a counting for /l and a call :sub
using a find /c is simpler to get the line count of a file.
using more +x avoids the need to differentiate the skip count.
when outputting only one line, directly use > to overwrite previous content.
Here using %~dp0 (batch folder) for input/output.
:: Q:\Test\2019\05\02\SO_55951454.cmd
#echo off
cd /d "%~dp0"
for /L %%L in (1,1,3) do Call :Sub %%L
Goto :Eof
:Sub
for /f %%i in ('find /C /V "" ^<"foto%1.txt"') do set count=%%i
set /a "rd=%random% %% count"
for /f "delims=" %%i in ('more +%rd% "foto%1.txt"') do set "var=%%i"&goto :cont
:cont
echo.%var%
>"urlfoto%1.txt" echo.%var%
Goto :Eof

Batch script not outputting files with this code

This script should output each word in a 10-word sentence stored in line 1 (When called with SeparateLine.bat (filename) 1, but it shows no errors nor outputs or makes the file.
I have already tried removing the parenthesis in the (echo %%a > 1.txt) and the ones below, with no avail. I've also tried different formats for where the outputs go, still no avail.
#echo off
if not exist "%~1" echo file not found & exit /b 1
if "%~2"=="" echo line not defined & exit /b
if "%~2"=="1" set line=1 & goto start
set /a line=%~2-1
:start
For /f "tokens=1,2,3,4,5,6,7,8,9,10* usebackq skip=%line% delims= " %%A in ("%~1") do (
if not "%%A"=="" (echo %%A > 1.txt)
if not "%%B"=="" (echo %%B > 2.txt)
if not "%%C"=="" (echo %%C > 3.txt)
if not "%%D"=="" (echo %%D > 4.txt)
if not "%%E"=="" (echo %%E > 5.txt)
if not "%%F"=="" (echo %%F > 6.txt)
if not "%%G"=="" (echo %%G > 7.txt)
if not "%%H"=="" (echo %%H > 8.txt)
if not "%%I"=="" (echo %%I > 9.txt)
if not "%%J"=="" (echo %%J > 10.txt)
GOTO endforloop
)
:endforloop
With the file that contains one, two, three... ten separated by spaces, it should output 10 files (maximum word limit is 10) each containing word 1-10 of the line (I specified line 1 in the second parameter as the words are on the first line), but the actual results are... nothing. Literally, it acts as if it completed successfully but no files are made and, well, no error codes.
I think this will be what you are looking for. Note you cannot use the pre-defined variable in skip=%line% you need to instead use more +%line%, there is not a need to define each token token=1,2,3,4... etc. simply use tokens1-10 and and last, but not least no need to use delims= as whitespace is the default delimeter:
#echo off
if not exist "%~1" echo file not found & exit /b 1
if "%~2"=="" echo line not defined & exit /b
if "%~2"=="1" set line=1 & goto start
set /a line=%~2-1
:start
For /f "tokens=1-10" %%A in ('type "%~1" ^| more +%line%') do (
if "%%A" NEQ "" echo %%A
if not "%%B"=="" echo %%B
if not "%%C"=="" echo %%C
if not "%%D"=="" echo %%D
if not "%%E"=="" echo %%E
if not "%%F"=="" echo %%F
if not "%%G"=="" echo %%G
if not "%%H"=="" echo %%H
if not "%%I"=="" echo %%I
if not "%%J"=="" echo %%J
goto :EOF
)
There is a flaw however with your line variable.
if a user selects 0 it will do 0 - = -1and then set the lines to skip-1if a user selects2it will set it to skip1` which is not what a user requested, so I suggest you clarify what your intensions are with the skip lines, but perhaps just get rid of it completely, like:
#echo off
if not exist "%~1" echo file not found & exit /b 1
if "%~2"=="" echo line not defined & exit /b
set /a line=%~2
:start
For /f "tokens=1-10" %%A in ('type "%~1" ^| more +%line%') do (
if "%%A" NEQ "" echo %%A
if not "%%B"=="" echo %%B
if not "%%C"=="" echo %%C
if not "%%D"=="" echo %%D
if not "%%E"=="" echo %%E
if not "%%F"=="" echo %%F
if not "%%G"=="" echo %%G
if not "%%H"=="" echo %%H
if not "%%I"=="" echo %%I
if not "%%J"=="" echo %%J
goto :EOF
)

How can I read the last 2 lines of a file in batch script

I have a Java program that appends new builds information in the last two lines of a file.
How can I read them in batch file?
This code segment do the trick...
for /F "delims=" %%a in (someFile.txt) do (
set "lastButOne=!lastLine!"
set "lastLine=%%a"
)
echo %lastButOne%
echo %lastLine%
EDIT: Complete TAIL.BAT added
This method may be modified in order to get a larger number of lines, that may be specified by a parameter. The file below is tail.bat:
#echo off
setlocal EnableDelayedExpansion
rem Tail command in pure Batch: Tail.bat filename numOfLines
rem Antonio Perez Ayala
for /F "delims=" %%a in (%1) do (
set /A i=%2, j=%2-1
for /L %%j in (!j!,-1,1) do (
set "lastLine[!i!]=!lastLine[%%j]!
set /A i-=1
)
set "lastLine[1]=%%a"
)
for /L %%i in (%2,-1,1) do if defined lastLine[%%i] echo !lastLine[%%i]!
2ND EDIT: New version of TAIL.BAT added
The version below is more efficient:
#echo off
setlocal EnableDelayedExpansion
rem Tail command in pure Batch, version 2: Tail.bat filename numOfLines
rem Antonio Perez Ayala
set /A firstTail=1, lastTail=0
for /F "delims=" %%a in (%1) do (
set /A lastTail+=1, lines=lastTail-firstTail+1
set "lastLine[!lastTail!]=%%a"
if !lines! gtr %2 (
set "lastLine[!firstTail!]="
set /A firstTail+=1
)
)
for /L %%i in (%firstTail%,1,%lastTail%) do echo !lastLine[%%i]!
This will solve the problem, where someFile.txt is the file where you want to read the lines from:
for /f %%i in ('find /v /c "" ^< someFile.txt') do set /a lines=%%i
echo %lines%
set /a startLine=%lines% - 2
more /e +%startLine% someFile.txt > temp.txt
set vidx=0
for /F "tokens=*" %%A in (temp.txt) do (
SET /A vidx=!vidx! + 1
set localVar!vidx!=%%A
)
echo %localVar1%
echo %localVar2%
del temp.txt
::change the values bellow with a relevant ones.
set "file=C:\some.file"
set "last_lines=2"
for /f %%a in ('findstr /R /N "^" "%file%" ^| find /C ":"') do #set lines=%%a
set /a m=lines-last_line
more +%m% "%file%"
Directly from the command line:
C:\>set "file=C:\some.file"
C:\>set "last_lines=5"
C:\>(for /f %a in ('findstr /R /N "^" "%file%" ^| find /C ":"') do #set lines=%a)&#set /a m=lines-last_lines&call more +%m% "%file%"

Dos batch script error? Error occurred while processing: .exe

In a DOS script that I wrote, I am unable to figure out what causes this error that I get:
The system cannot find the file specified.
Error occurred while processing: .exe.
Here is the script. Any help would be greatly appreciated. I tried to ask for help on the DosTips forum but I am getting no answer. :
#echo off
:: script to edit property files
CALL :PROPEDIT # Key4 Value446 test.properties
GOTO :END
:PROPEDIT [#] PropKey PropVal File
IF "%~1"=="#" (
:: Passing a first argument of "#" will disable the line while editing
SET "_PREFIX=#"
SHIFT
)
IF NOT "%~4"=="" (
ECHO Too many arguments.
EXIT /B 1
)
IF "%~3"=="" (
ECHO PROPEDIT: Function requires 3 args: [#] PropKey PropVal File
EXIT /B 1
) ELSE (
SET "_PROPKEY=%~1"
SET "_PROPVAL=%~2"
SET "_FILE=%~3"
)
MOVE /Y "%_FILE%" "%_FILE%.bak">nul
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE "%_FILE%.bak" ^|FINDSTR /N /I "%_PROPKEY%="`) DO (
SET LINE=%%A
)
FOR /F "tokens=1,2* delims=:" %%S IN ("%LINE%") DO SET LINE=%%S
SET /A COUNT=1
FOR /F "USEBACKQ delims=" %%A IN (`TYPE "%_FILE%.bak" ^|FIND /V /N ""`) DO (
SET "LN=%%A"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "LN=!LN:*]=!"
IF "!COUNT!" NEQ "%LINE%" (
ECHO(!LN!>>%_FILE%
) ELSE (
ECHO %_PREFIX%%_PROPKEY%=%_PROPVAL%>>%_FILE%
ECHO Updated '%_FILE%' with value '%_PREFIX%%_PROPKEY%=%_PROPVAL%'.
)
ENDLOCAL
SET /A COUNT+=1
)
EXIT /B 0
:END
ECHO --- Finished Test ---
pause
Remove the .EXE of FIND and TYPE
You don't need TYPE. You can do just this:
FOR /F "tokens=*" %%A IN (`FIND /N /I "%_PROPKEY%=" "%_FILE%.bak"`) DO (
If FIND spoils your results (by not using TYPE) then consider using FINDSTR instead and use 'DELIMS=:' instead of 'DELIMS=]'
If I'm right my assumption that the following is helpful, take a look at the 'MORE +nnn' command (note the '+nnn' which outputs lines from a specific location in the file).
Why not just place your 'SETLOCAL ENABLE.. etc' at the top of your code?
If you explain what it is you're trying to attempt, then I might be in a better position to help.
Just a few thoughts :)
Here is the working code after getting some help from Paul Tomasi:
#echo off
SETLOCAL DISABLEDELAYEDEXPANSION
CALL :PROPEDIT # Key4 Value446 test.properties
GOTO :END
:PROPEDIT [#] PropKey PropVal File
IF "%~1"=="#" (
:: Passing a first argument of "#" will disable the line while editing
SET "_PREFIX=#"
SHIFT
)
IF NOT "%~4"=="" (
ECHO Too many arguments.
EXIT /B 1
)
IF "%~3"=="" (
ECHO PROPEDIT: Function requires 3 args: [#] PropKey PropVal File
EXIT /B 1
) ELSE (
SET "_PROPKEY=%~1"
SET "_PROPVAL=%~2"
SET "_FILE=%~3"
)
MOVE /Y "%_FILE%" "%_FILE%.bak">nul
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE "%_FILE%.bak" ^|FINDSTR /N /I "%_PROPKEY%="`) DO (
SET LINE=%%A
)
FOR /F "tokens=1,2* delims=:" %%S IN ("%LINE%") DO SET LINE=%%S
SET /A COUNT=1
FOR /F "USEBACKQ delims=" %%A IN (`TYPE "%_FILE%.bak" ^|FIND /V /N ""`) DO (
SET "LN=%%A"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "LN=!LN:*]=!"
IF "!COUNT!" NEQ "%LINE%" (
ECHO(!LN!>>%_FILE%
) ELSE (
ECHO %_PREFIX%%_PROPKEY%=%_PROPVAL%>>%_FILE%
ECHO Updated '%_FILE%' with value '%_PREFIX%%_PROPKEY%=%_PROPVAL%'.
)
SETLOCAL DISABLEDELAYEDEXPANSION
SET /A COUNT+=1
)
EXIT /B 0
:END
ECHO --- Finished Test ---
pause

Resources