Batch file to update a csv file on condition if file exists - batch-file

Below is the Report.csv file, where I need to update the Status column based on the condition, I file in Lockbox exist. I have written the code for if file exist or not, but don't know how to update the Status column.
Lockbox Location Status Reason(N)
3080 Minot Y
1780 Minot N Not Scheduled
2280 Minot Y
3015 Windsor Y
2215 Windsor Y
1515 Windsor Y
29011 Windsor Y
Below is the code I have written. Please help..
#echo off
setlocal
set count=0
echo %time%
echo %date%
set y=%Date:~10,5%
set m=%Date:~4,2%
set d=%Date:~7,2%
if "%time:~0,1%"==" " (set tym=0%time:~1,1%) ELSE set tym=%time:~0,2%
set tm=%tym%%time:~2,0%
echo %tm%
pause
set pattern1=INGFINS.IMAGE.image1.29011.%y%%m%%d%%tm%
set pattern2=INGFINS.IMAGE.image2.2215.%y%%m%%d%%tm%
set pattern3=INGFINS.IMAGE.image3.1515.%y%%m%%d%%tm%
set pattern4=INGFINS.IMAGE.image4.3015.%y%%m%%d%%tm%
set pattern5=INGFINS.IMAGE.image5.1780.%y%%m%%d%%tm%
set pattern6=INGFINS.IMAGE.image6.2280.%y%%m%%d%%tm%
set pattern7=INGFINS.IMAGE.image7.3080.%y%%m%%d%%tm%
IF EXIST "C:\Users\Desktop\zipLocation\*%pattern1%*.<" (
ECHO "%pattern1% exist"
) ELSE (
ECHO "%pattern1% not exist"
)
IF EXIST "C:\Users\Desktop\zipLocation\*%pattern2%*.<" (
ECHO "%pattern2% exist"
) ELSE (
ECHO "%pattern2% not exist"
)
IF EXIST "C:\Users\Desktop\zipLocation\*%pattern3%*.<" (
ECHO "%pattern3% exist"
) ELSE (
ECHO "%pattern3% not exist"
)
IF EXIST "C:\Users\Desktop\zipLocation\*%pattern4%*.<" (
ECHO "%pattern4% exist"
) ELSE (
ECHO "%pattern4% not exist"
)
IF EXIST "C:\Users\Desktop\zipLocation\*%pattern5%*.<" (
ECHO "%pattern5% exist"
) ELSE (
ECHO "%pattern5% not exist"
)
IF EXIST "C:\Users\Desktop\zipLocation\*%pattern6%*.<" (
ECHO "%pattern6% exist"
) ELSE (
ECHO "%pattern6% not exist"
)
IF EXIST "C:\Users\Desktop\zipLocation\*%pattern7%*.<" (
ECHO "%pattern7% exist") ELSE (
ECHO "%pattern7% not exist"
)
rem call "statusReport.vbs"
endlocal
pause

Although some other users tend to close your question, I give next solution hoping that it could help. Commented .bat script:
#ECHO OFF >NUL
SETLOCAL EnableExtensions DisableDelayedExpansion
rem set input and output files: change to meet your circumstances
set "_fileIn=d:\bat\so\files\39587196_Report.TSV" tab-separated values
set "_fileOut=d:\bat\so\files\39587196_ReportOut.csv" comma-separated values
rem empty output file
>"%_fileOut%" type NUL
rem show input file
type "%_fileIn%"
echo(
rem obtain %_datetime% variable in locale independent yyyymmddHHMMSS format
for /f "tokens=2 delims==" %%G in (
'wmic OS get localdatetime /value') do set "_datetime=%%G"
set "_datetime=%_datetime:~0,14%"
rem reduce %_datetime% variable to yyyymmddHH format as the OQ does
set "_datetime=%_datetime:~0,10%"
set count=0
echo %date% %time%
echo %_datetime%
set "_pattern1=INGFINS.IMAGE.image1.29011.%_datetime%"
set "_pattern2=INGFINS.IMAGE.image2.2215.%_datetime%"
set "_pattern3=INGFINS.IMAGE.image3.1515.%_datetime%"
set "_pattern4=INGFINS.IMAGE.image4.3015.%_datetime%"
set "_pattern5=INGFINS.IMAGE.image5.1780.%_datetime%"
set "_pattern6=INGFINS.IMAGE.image6.2280.%_datetime%"
set "_pattern7=INGFINS.IMAGE.image7.3080.%_datetime%"
set "_pattern8=INGFINS.IMAGE.image7.8888.%_datetime%" for testing purposes
set "_ForGDelims= delims=," CSV input: delimiter is Comma (0x2C Comma)
set "_ForGDelims=" TSV input: delimiter is Tab (0x09 Character Tabulation)
if /I "%_fileIn:~-4%"==".tsv" set "_ForGDelims=" soft-code instead of above line
set "_csvHeader=" CSV header not processed yet
rem iterate input file, line by line, tokenized
for /F "usebackq tokens=1,2,3,*%_ForGDelims%" %%G in ("%_fileIn%") do (
set "_Lockbox=%%~G"
set "_Location=%%~H"
set "_Status=%%~I"
set "_Reason=%%~J"
if defined _csvHeader (
rem show checked Lockbox value (no NewLine)
<NUL set /P "=checking %%~G"
set "_LockboxFoundInVariable="
rem iterate all _pattern* variables
for /F "tokens=1,2 delims==" %%g in ('set _pattern') do (
rem take 4th token in %_pattern*% value
for /F "tokens=4 delims=." %%# in ("%%~h") do (
if "%%#"=="%%~G" (
echo - found %%G in %%g:%%h
set "_LockboxFoundInVariable=%%g"
rem ??? I don't comprehend what this ↓ LessThan should mean ???
IF EXIST "C:\Users\Desktop\zipLocation\*%%h*.<" (
rem ??? I don't comprehend what this ↑ LessThan should mean ???
set "_Status=y" pattern exists
) ELSE (
set "_Status=n" pattern does not exist
)
)
)
)
rem echo NewLine if necessary i.e. if checked Lockbox value not in any _pattern*
if not defined _LockboxFoundInVariable (echo()
) else (
set "_csvHeader=anything" CSV header processed already
)
call :csvLineOut
)
rem show output file
echo(
type "%_fileOut%"
ENDLOCAL
goto :eof
:csvLineOut
rem you could use <TAB>s ↓ ↓ ↓ instead of commas
>>"%_fileOut%" echo %_Lockbox%,%_Location%,%_Status%,"%_Reason%"
goto :eof
Please read Delimiter-separated values about .csv vs. .tsv difference. Note that I don't keep using quotation marks to surround every field strictly…
Output:
==> D:\bat\SO\39587196.bat
Lockbox Located Status Reason(N)
3080 Minot Y
1111 Test Y
1780 Minot N Not Scheduled
2280 Minot Y
2215 Windsor Y
29011 Windsor Y
9999 Test Y
20.09.2016 17:41:53,87
2016092017
checking 3080 - found 3080 in _pattern7:INGFINS.IMAGE.image7.3080.2016092017
checking 1111
checking 1780 - found 1780 in _pattern5:INGFINS.IMAGE.image5.1780.2016092017
checking 2280 - found 2280 in _pattern6:INGFINS.IMAGE.image6.2280.2016092017
checking 2215 - found 2215 in _pattern2:INGFINS.IMAGE.image2.2215.2016092017
checking 29011 - found 29011 in _pattern1:INGFINS.IMAGE.image1.29011.2016092017
checking 9999
Lockbox,Located,Status,"Reason(N)"
3080,Minot,n,""
1111,Test,Y,""
1780,Minot,n,"Not Scheduled"
2280,Minot,n,""
2215,Windsor,n,""
29011,Windsor,n,""
9999,Test,Y,""
==>
Further resources (required reading, incomplete):
(command reference) An A-Z Index of the Windows CMD command line
(helpful particularities) Windows CMD Shell Command Line Syntax
(%~G, %~H etc. special page) Command Line arguments (Parameters)
(special page) EnableDelayedExpansion
(>, >> etc. special page) Redirection
(%_fileIn:~-4% etc.) Extract part of a variable (substring)
(%% doubled percent sign) Escape Characters, Delimiters and Quotes

Related

Rename value in column via batch

I have a tab delimited txt file and I am trying to find the value 0 in the last column in every line then rename that value from 0 to K.This is the code I have come up with so far but I can't get the values to change. What am I doing wrong here?
ECHO ON
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=E:\psexport"
SET "destdir=E:\psexport"
SET "filename1=%sourcedir%\nk3.txt"
SET "outfile=%destdir%\nk4.txt"
(
FOR /f * IN ("%filename1%") DO (
SET "line=*"
SET "line=!line:0=K"
ECHO !line!
)
)>"%outfile%"
GOTO :EOF
`
You are using bang where I would expect to see percentage. Also, I'm not sure about that second set statement.
See my code example below. In the echo command I am calling line, with the variable substitution of replace 0 with K. It's wrapped in percentages because that whole expression is the variable we want to echo.
ECHO ON
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=E:\psexport"
SET "destdir=E:\psexport"
SET "filename1=%sourcedir%\nk3.txt"
SET "outfile=%destdir%\nk4.txt"
(
FOR /f * IN ("%filename1%") DO (
SET "line=*"
ECHO %line:0=K%
)
)>"%outfile%"
GOTO :EOF
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=E:\psexport"
SET "destdir=E:\psexport"
SET "filename1=%sourcedir%\nk3.txt"
SET "outfile=%destdir%\nk4.txt"
(
FOR /f "usebackq delims=" %%a IN ("%filename1%") DO (
SET "line=%%a"
IF "!line:~-2!"==" 0" (
ECHO !line:~0,-2! K
) ELSE (
ECHO %%a
)
)
)>"%outfile%"
GOTO :EOF
The for syntax requires a metavariable - I've used %%a - which is alphabetical and case-sensitive.
The modifier usebackq is used because the name of the file being read is quoted.
delims= means no delimiters, so the entire file line is delivered to %%a.
To use substringing, we need to transfer the value to a standard environment variable, then test that the last two characters of the line read are 0 so that 10 does not get modified. If the test is true, echo the line from the beginning (character 0) through to the end - 2 characters and append K, otherwise, regurgitate the original line.
The set syntax you were using replaces every 0 with K.

loop through a text file and insert a line with batch file

I am trying to search through a text file for keywords, then insert a number of lines after a specific line/keyword (not end of file).
My code can find the keywords, however I am struggling to add the lines. My code adds the line to the end of the file, so the bit I need help with is after :ADD THE TEXT.
myfile.text looks like:
QFU;
text2;
LastUpdate=20180323;
text3;
I would like to add a list of static lines after LastUpdate, which makes the file look like:
QFU;
text2;
LastUpdate=20180323;
Inserted text1
Inserted text2
text3;
This is my code:
#echo
SET /A COND1=0
for /F "tokens=*" %%i in (myfile.txt) do call :process %%i
goto thenextstep
:process
set VAR1=%1
IF "%VAR1%"=="QFU" SET /A COND1=1
IF "%VAR1%"=="QFU" (
msg * "QFU line found !!"
)
:If QFU line is found then look for Last update
IF "%COND1%"=="1" IF "%VAR1%"=="LastUpdate" (
msg * "LastUpdate line found !!"
:ADD THE TEXT
echo. text to be added>>myfile.txt
:reset COND1 to 0
set /A COND1=0
)
#echo off
setlocal enabledelayedexpansion
call :get_insert_index
if not defined index (
>&2 echo index not defined.
exit /b 1
)
set "i=0"
(
for /f "tokens=*" %%A in (myfile.txt) do (
set /a "i+=1"
echo %%A
for %%B in (%index%) do if !i! equ %%B (
echo --- INSERT
)
)
) > myupdate.txt
exit /b
:get_insert_index
setlocal enabledelayedexpansion
set "i=0"
set "qfu="
set "total="
for /f "tokens=*" %%A in (myfile.txt) do (
set /a i+=1
set "line=%%~A"
if "%%~A" == "QFU;" (
set /a "qfu=!i! + 1"
) else if "!line:~,11!" == "LastUpdate=" (
if defined qfu (
if !i! gtr !qfu! (
if defined total (set total=!total! !i!) else set total=!i!
set "qfu="
)
)
)
)
endlocal & set "index=%total%"
exit /b
This will insert text after the 1st line starting with LastUpdate=,
after the line of QFU;, but not the line starting with LastUpdate=
which is the next line after QFU;.
The label :get_insert_index is called and uses a for loop
to read myfile.txt to get the line index of LastUpdate=
mentioned in the above paragraph.
The variable qfu stores the line index + 1 of QFU; so
LastUpdate= cannot be matched on the next line.
If gfu and LastUpdate= is found and the line index is
greater then gfu, then the line index is appended to total.
qfu is undefined to avoid further matches to LastUpdate=
until QFU; is matched again.
The loop will end and the global variable index is set the
value of total. The label returns control back to the caller.
index is checked if defined at the top of the script after
the call of the label.
The top for loop reads myfile.txt and echoes each line read.
The nested for loop checks the index variable to match the
current line index and if equal, will echo the new text.
The echoes are redirected to myupdate.txt.
Used substitution of "!line:~,11!" so view set /? for help.
Used enabledelayedexpansion so view setlocal /? for help.
Text using ! may find ! being interpreted as a variable
so avoid using !.
Used gtr which can be viewed in if /?. gtr is
"Greater than".
Alternative to avoid creation of an index:
#echo off
setlocal enabledelayedexpansion
set "i=0"
set "gfu="
for /f "tokens=*" %%A in (myfile.txt) do (
set /a i+=1
set "line=%%~A"
>> myupdate.txt echo(%%A
if "%%~A" == "QFU;" (
set /a "qfu=!i! + 1"
) else if "!line:~,11!" == "LastUpdate=" (
if defined qfu (
if !i! gtr !qfu! (
>> myupdate.txt echo --- INSERT
set "qfu="
)
)
)
)
exit /b
>> myupdate.txt echo(%%A writes each line.
>> myupdate.txt echo --- INSERT writes new line to insert.
If system memory permits based on file size, this is much faster:
#echo off
setlocal enabledelayedexpansion
set "i=0"
set "gfu="
(
for /f "tokens=*" %%A in (myfile.txt) do (
set /a i+=1
set "line=%%~A"
echo(%%A
if "%%~A" == "QFU;" (
set /a "qfu=!i! + 1"
) else if "!line:~,11!" == "LastUpdate=" (
if defined qfu (
if !i! gtr !qfu! (
echo --- INSERT
set "qfu="
)
)
)
)
) > myupdate.txt
exit /b
Used on 2.74 MB file, Time reduced from 70s to 21s. The write handle to myupdate.txt remains open for the entire loop, thus the write is cached.

Split string in batch file

I am new to using batch files so could someone please help me split a string i am getting from a file.
I am using %USERPROFILE% to get my string.
The string is: "C:\Users\nicholas"
I would like to keep the C:\ part, but get rid of the \Users\nicholas part.
for /f "tokens=2 delims=\" %A in ('set userprofile') do echo %A\
See for /?
Also
echo %userprofile:~0,3%
If you carefully read the output of set /?, you'll find the answer:
May also specify substrings for an expansion.
%PATH:~10,5%
would expand the PATH environment variable, and then use only the 5
characters that begin at the 11th (offset 10) character of the expanded
result.
So, you can use something like this to get the first 3 characters of your string:
> echo %userprofile:~0,3%
C:\
I As you need the drive where where the users are located you can use directly
%systemdrive% variable - this is the drive where the windows is installed
II the easiest way to get a drive from path:
for %%a in ("%userprofile%") do echo %%~da\
%~da - expands a path to its drive only
III over-complicated but powerful way (split function that can be used for a different things):
#echo off
call :split "%userprofile%" "\" 1 drive
echo %drive%\
goto :eof
:split [%1 - string to be splitted;%2 - split by;%3 - possition to get; %4 - if defined will store the result in variable with same name]
::http://ss64.org/viewtopic.php?id=1687
setlocal EnableDelayedExpansion
set "string=%~2%~1"
set "splitter=%~2"
set /a position=%~3
set LF=^
rem ** Two empty lines are required
echo off
for %%L in ("!LF!") DO (
for /f "delims=" %%R in ("!splitter!") do (
set "var=!string:%%~R%%~R=%%~L!"
set "var=!var:%%~R=%%~L!"
if "!var!" EQU "!string!" (
echo "%~1" does not contain "!splitter!" >&2
exit /B 1
)
)
)
if "!var!" equ "" (
endlocal & if "%~4" NEQ "" ( set "%~4=")
)
if !position! LEQ 0 ( set "_skip=" ) else (set "_skip=skip=%position%")
for /f "eol= %_skip% delims=" %%P in (""!var!"") DO (
if "%%~P" neq "" (
set "part=%%~P"
goto :end_for
)
)
set "part="
:end_for
if not defined part (
endlocal
echo Index Out Of Bound >&2
exit /B 2
)
endlocal & if "%~4" NEQ "" (set %~4=%part%) else echo %part%
exit /b 0

Batch-file programing to get specified line into variable by checking other key word

Im trying to write batch file code to check whether given line is present in text file or not. If it is present I want to get specific line(depending on line number) after that line into variable..
Can anyone help me?
For example
I have text file as...
EX1
EX2
Ex3
EX4
Ex5
now I want to search weather Ex3 is present in batch file or not.
If it is present I want Ex5(2nd line after that) into variable.
Thanks in advance
This works on my box:
#echo off
SET searchterm=Ex3
SET /a lineafter=2
SET filename=lst.txt
:: --------------
SETLOCAL ENABLEDELAYEDEXPANSION
SET /a c=0
FOR /F "delims=" %%i IN (%filename%) DO (
if !c! GTR 0 (
IF %lineafter% EQU !c! (
SET result=%%i
GOTO :linefound
)
SET /a c=!c! + 1
) ELSE (
IF "%%i"=="%searchterm%" (
SET /a c=1
)
)
)
echo No result
GOTO :EOF
:linefound
echo Result: %result%
Just enter your values in the lines 2-4.

How to receive even the strangest command line parameters?

as discussed in an other thread How to avoid cmd.exe interpreting shell special characters like < > ^
it is not easy to get all parameters from the command line.
A simple
set var=%1
set "var=%~1"
are not enough, if you have a request like
myBatch.bat abc"&"^&def
I have one solution, but it needs a temporary file, and it is also not bullet proof.
#echo off
setlocal DisableDelayedExpansion
set "prompt=X"
(
#echo on
for %%a in (4) do (
rem #%1#
)
) > XY.txt
#echo off
for /F "delims=" %%a in (xy.txt) DO (
set "param=%%a"
)
setlocal EnableDelayedExpansion
set param=!param:~7,-4!
echo param='!param!'
It fails with something like myBatch.bat %a, it display 4 not the %a
in this situation a simple echo %1 would work.
It's obviously the for-loop but I don't know how to change this.
Perhaps there exists another simple solution.
I don't need this to solve an actual problem, but I like solutions that are bullet proof in each situation, not only in the most cases.
I don't think anyone found any holes in this, except for the inability to read newlines in the parameters:
#echo off
setlocal enableDelayedExpansion
set argCnt=1
:getArgs
>"%temp%\getArg.txt" <"%temp%\getArg.txt" (
setlocal disableExtensions
set prompt=#
echo on
for %%a in (%%a) do rem . %1.
echo off
endlocal
set /p "arg%argCnt%="
set /p "arg%argCnt%="
set "arg%argCnt%=!arg%argCnt%:~7,-2!"
if defined arg%argCnt% (
set /a argCnt+=1
shift /1
goto :getArgs
) else set /a argCnt-=1
)
del "%temp%\getArg.txt"
set arg
The above comes from a lively DosTips discussion - http://www.dostips.com/forum/viewtopic.php?p=13002#p13002. DosTips user Liviu came up with the critical SETLOCAL DisableExtensions piece.
The code below is based on the rambling Foolproof Counting of Arguments topic on DosTips and this answer by jeb:
#echo off & setLocal enableExtensions disableDelayedExpansion
(call;) %= sets errorLevel to 0 =%
:: initialise variables
set "paramC=0" & set "pFile=%tmp%\param.tmp"
:loop - the main loop
:: inc param counter and reset var storing nth param
set /a paramC+=1 & set "pN="
:: ECHO is turned on, %1 is expanded inside REM, GOTO jumps over REM,
:: and the output is redirected to param file
for %%A in (%%A) do (
setLocal disableExtensions
set prompt=#
echo on
for %%B in (%%B) do (
#goto skip
rem # %1 #
) %= for B =%
:skip - do not re-use this label
#echo off
endLocal
) >"%pFile%" %= for A =%
:: count lines in param file
for /f %%A in ('
find /c /v "" ^<"%pFile%"
') do if %%A neq 5 (
>&2 echo(multiline parameter values not supported & goto die
) %= if =%
:: extract and trim param value
for /f "useBack skip=3 delims=" %%A in ("%pFile%") do (
if not defined pN set "pN=%%A"
) %= for /f =%
set "pN=%pN:~7,-3%"
:: die if param value is " or "", else trim leading/trailing quotes
if defined pN (
setLocal enableDelayedExpansion
(call) %= OR emulation =%
if !pN!==^" (call;)
if !pN!=="" (call;)
if errorLevel 1 (
for /f delims^=^ eol^= %%A in ("!pN!") do (
endLocal & set "pN=%%~A"
) %= for /f =%
) else (
>&2 echo(empty parameter values (""^) not supported & goto die
) %= if errorLevel =%
) else (
:: no more params on cmd line
set /a paramC-=1 & goto last
) %= if defined =%
:: die if param value contains "
if not "%pN:"=""%"=="%pN:"=%" (
>&2 echo(quotes (^"^) in parameter values not supported & goto die
) %= if =%
:: assign nth param, shift params, and return to start of loop
set "param%paramC%=%pN%" & shift /1 & goto loop
:last - reached end of params
:: no param values on cmd line
if %paramC% equ 0 (
>&2 echo(no parameter values found & goto die
) %= if =%
:: list params
set param
goto end
:die
(call) %= sets errorLevel to 1 =%
:end
:: exit with appropriate errorLevel
endLocal & goto :EOF
The following conditions will terminate the program immediately:
no parameters found
multiline parameter
empty parameter (""", or " is permitted for the last parameter)
one or more quotes (") in a parameter value
To ease these restrictions, simply comment out the relevant lines. Read the inline comments for more information. Do not attempt to turn off the multiline parameter trap!
I invented the syntax-error-technic to solve the problem (partially).
With this solution it's even possible to receive multiline parameters and also carriage return characters.
There is no known parameter which fails!
BUT the drawback of this solution, the main process exits and only a child process continues.
That is a consequence of the capture trick, a syntax error is created by using an invalid parenthesis block ( Prepare ) PARAMS....
But the syntax error itself outputs the complete block, including the expanded value of %*.
The output is redirected to a file by the permanent redirect technic.
And the child process can retrieve the complete parameter from the file.
This solution can be useful, when the batch file only handles the parameter and always exit afterwards.
#echo off
REM *** Thread redirector
for /F "tokens=3 delims=:" %%F in ("%~0") do goto %%F
REM *** Clear params.tmp
break > params.tmp
start "" /b cmd /k "%~d0\:StayAlive:\..\%~pnx0 params.tmp"
(set LF=^
%=empty=%
)
REM *** Change prompt for better recognition
prompt #PROMPT#
REM *** Change streams permanently
REM *** stream1 redirects to params.tmp
REM *** stream2 redirects to nul
echo on >nul 2>nul 0>nul 3>params.tmp 4>nul 5>&3
#REM *** This is the magic part, it forces a syntax error, the error message itself shows the expanded %asterix without ANY modification
( Prepare ) PARAMS:%LF%%*%LF%
echo Works
exit /b
REM *** Second thread to fetch and show the parameters
:StayAlive
:__WaitForParams
if %~z1 EQU 0 (
goto :__WaitForParams
)
REM *** Show the result
findstr /n "^" %1
It's up to the user who types the command to escape any special characters. Your program cannot do anything about what the shell does before your program even runs. There is no other "bullet proof" solution to this.

Resources