I'm trying to grab a couple of lines in some files and store them in variables (line3 and line4).
Here is the code:
setlocal EnableDelayedExpansion
for /f "tokens=*" %%a in ('dir *.md /b /o:-n /a:-d') do (
call :getLines "%%a"
)
pause
exit
:getLines
set /A cnt=2
for /f "skip=4 tokens=*" %%b in (%1) do (
set /A cnt+=1
set "line!cnt!=%%b"
if !cnt! == 4 (
set "filename=%~n1"
set "blogdate=!filename:~0,10!"
set "blogtitle=!filename:~11!"
echo hello
echo !line3!
echo !line4!
echo !filename!
echo !blogdate!
echo !blogtitle!
)
)
goto :eof
The above will not even echo hello. I can't see what's wrong.
This is what each file looks like:
# Title
*2015-11-17*
Tags: word1 word2
First Sentence is here.
Filenames look like this:
2015-11-17-title.md
You passed to call with quotes, so you should strip it first (or use usebackq).
Also when you are testing, don't use exit yet.
Try this, see if it works:
(Formatted so the structure is more clear, try comment #echo off to get more details.)
#echo off
setlocal EnableDelayedExpansion
for /f "tokens=*" %%a in ('dir *.md /b /o:-n /a:-d') do (
call :getLines "%%a"
)
pause
::exit
goto :eof
:getLines
set /A cnt=2
for /f "usebackq skip=4 tokens=*" %%b in (%1) do (
set /A cnt+=1
set "line!cnt!=%%b"
if !cnt! == 4 (
set "filename=%~n1"
set "blogdate=!filename:~0,10!"
set "blogtitle=!filename:~11!"
echo hello
echo !line3!
echo !line4!
echo !filename!
echo !blogdate!
echo !blogtitle!
goto :eof
)
)
goto :eof
for will take the input with quotes as string not as file.
%~1 will strip %1's quotes.
Check for /? and call /? for more details.
Related
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.
I was trying this, it'll count file's line after I copy the file's path (Shift+right click >copy as path) and put it in batch file, but.... how do I fix it??
the last \ in %path% is causing problem.
#echo off
Setlocal EnableDelayedExpansion
set /p ifilename=Enter file name:
for %%f in (%ifilename%) do (
set paath=%%~df%%~pf
set ifilename=%%~nf%%~xf
)
echo %paath%
echo %ifilename%
for /f "usebackq" %%a in (`dir /b /s %1 "%paath%"`) do (
for /f "usebackq" %%b in (`type %ifilename% ^| find "" /v /c`) do (
set lines= %%b
)
)
echo %lines%
pause
>> the last \ in %path% is causing problem
It's easy to solve this , the code is :
set TempDir=C:\0TEMP
#echo off
md %TempDir%
cd /d %TempDir%
::------
#echo off
#echo on
Setlocal EnableDelayedExpansion
::set /p ifilename=Enter file name:
SET DUMMYexe=%TempDir%\DUMMY.exe
IF EXIST "%DUMMYexe%" goto ll123
ECHO ---------writing
pause
(
ECHO pause1
ECHO pause2
ECHO pause3
) > %DUMMYexe%
:ll123
SET ifilename=%DUMMYexe%
for %%f in (%ifilename%) do (
set fpath=%%~df%%~pf
set ifilename=%%~nf%%~xf
)
echo %fpath%
echo %ifilename%
SET v=asdf1234
SET vv=\%v%
SET vvv=%fpath%%vv%
CALL SET v=%%vvv:\%vv%=%%
echo 111---%v%
pause
set fpath=%v%
for /f "usebackq" %%a in (`dir /b /s %1 "%fpath%"`) do (
for /f "usebackq" %%b in (`type %ifilename% ^| find "" /v /c`) do (
set lines= %%b
)
)
echo %lines%
echo on
pause
goto
But of course, if I use the var 'path', my win10 will report :
'find' is not recognized as an internal or external command, operable program or batch file.
BTW, Maybe you'd be interested in the code below :
SETLOCAL ENABLEDELAYEDEXPANSION
SET count=1
FOR /F "tokens=* USEBACKQ" %%F IN (`dir `) DO (
SET var!count!=%%F
SET /a count=!count!+1
)
ECHO -------------- %count%
ECHO
ECHO %var1%
ECHO %var2%
ECHO %var3%
ENDLOCAL
pause
which I tested after copying from:
How to set commands output as a variable in a batch file
Very useful info about "Setlocal EnableDelayedExpansion" can be found in:
How do SETLOCAL and ENABLEDELAYEDEXPANSION work?
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
)
I am having trouble with a bit of code, I don't really know how to describe it
but I can explain what doesn't work
FOR /D /r "%cd%\files\" %%G in ("*") DO (
echo In folder: %%~nxG
set /a count=1
echo %%~fG
For /R "%%~fG" %%B in ("*.mp3") do (
call :subroutine "%%~nB"
) & echo. >>%archive%.txt
)
just if you want to know what the subroutine does:
:subroutine
echo %count%:%1>>%archive%.txt
echo %count%: %1
set /a count+=1
GOTO :eof
I figured out that it doesn't read the %%~fG inside the second for loop.
Can someone please help me.
I am using SETLOCAL EnableDelayedExpansion
Thank you in advance.
Unfortunately you'll need another subroutine as for options are parsed before outer for tokens. Check the following example:
#echo off
echo :::ATTEMPT 1:::
for %%a in (z) do (
rem the expected delimiter is z and result should be ++::%%a
for /f "delims=%%a tokens=1,2" %%A in ("++z%%%%az--") do echo %%A::%%B
)
echo :::ATTEMPT 2:::
for %%a in (z) do (
call :subr "%%~a"
)
exit /b
:subr
rem the expected delimiter is z and result should be ++::%%a
for /f "delims=%~1 tokens=1,2" %%A in ("++z%%%%az--") do echo %%A::%%B
the output is:
:::ATTEMPT 1:::
++z::zz--
:::ATTEMPT 2:::
++::%%a
As you can see in the first attempt the %%a symbols are taken as delimiters. But subroutine arguments are parsed imminently so they can be used.
To make your code work you can try with:
FOR /D /r "%cd%\files\" %%G in ("*") DO (
echo In folder: %%~nxG
set /a count=1
echo %%~fG
call ::innerFor "%%~fG"
)
...
exit /b %errorlevel%
:innerFor
For /R "%~1" %%B in ("*.mp3") do (
call :subroutine "%%~nB"
) & echo. >>%archive%.txt
For /R "%%~fG" %%B in ("*.mp3") do (
Sadly, for/r can't be run with a variable as the dirname.
I'd suggest
call :anothersubroutine "%%~fG"
and
:anothersubroutine
For /R "%~1" %%B in ("*.mp3") do (
but I've not tried it. Perhaps you'd need to set %%~fG into a variable and use %var% (not tried that either...)
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