Windows command SET seems possibly redundant? - batch-file

I've inherited a batch file which reads major, minor and build numbers from a text file as part of a long-established build process - the actual reading part code is a simple FOR /F:
FOR /F "tokens=1,2,3* delims=." %%A IN (C:\MyBuildArea\version.txt) DO (
SET Major=%%A
SET Minor=%%B
SET Build=%%C
)
However this is followed by the line:
SET Build=%Build: =%
I don't understand this last line - what it is doing. Guessing it might be trying to catch and remove a trailing space (?) from the original file read as the FOR /F was delimited on dot (".") not space.
Hoping someone can help me understand - is this line redundant or serving some purpose?

The command SET Build=%Build: =% will simply substitute all spaces with nothing, i.e. it will remove all spaces in the text stored in Build.
See set /? on command prompt for details.

Related

extract number from string from another file

I am currently working on a batch file that is supposed to read a version number from another file.
Basically, I just need to extract the string from the other document and get the number from it (number changes over time).
set dir=..\folder1\file1.vcxproj
:: I want to get a string from %dir% with a specific beginning and then extract the version number from it
set string=... ("<PlatformToolset>*")
set vernum=... ("..>v142<..)
Thats what I want to achieve:
echo %string%
<PlatformToolset>v142</PlatformToolset>
echo %vernum%
142
I hope I could describe my problem. Unfortunately I have little experience with cmd and it is difficult for me to articulate myself in this respect.
I hope someone can still help :)
dir is a poor name for a variable for two reasons. First dir is a keyword in batch, and then it implies that it's a directory when it seems to be a file.
Use set "var1=value" for setting STRING values - this avoids problems caused by trailing spaces. Quotes are not needed for setting arithmetic values (set /a)
So presuming that what you're doing is to extract the 142 from the string <PlatformToolset>v142</PlatformToolset> found in the file dir (please change that name)
for /f "tokens=1,2delims=<> " %%b in ('type "%dir%"') do if "%%b"=="PlatformToolset" set "vernum=%%c"
set "vernum=%vernum:~1%"
note that the location and quote type (' or ") are critical.
The for reads each line of the file and analyses that line, assigning the first "token" (1) to %%b and the second (2) to %%c.
The line is regarded as being
<delimiter sequence><token1><delimiter sequence><token2><delimiter sequence><token3><delimiter sequence><token4>
A delimiter sequence is one or more of any of the characters specified in the delims= option; in this case, <, > and Space
So - where %%a (token 1) is PlatformToolset, we want to assign %%c (token 2) to vernum
so vernum will become v142 with a file containing the test line you've posted.
And the hieroglyphics behind the set command is explained by set /? from the prompt - it takes the value in vernum, starting at "character 1" (where the character numbering starts at 0) and assigns the result to the variable vernum
for more detail about for gymnastics, see for /? from the prompt.

Remove certain characters in a string using Windows command line

I have a text file having the string:
pub:
04:d6:b6:f2:98:ff:94:d8:3c:36:ad:5f:86:40:aa:
d1:5a:e1:87:5d:55:9d:ad:8b:2b:fc:18:e7:bb:47:
7f:9f:9a:62:c6:19:3a:9e:65:62:4e:5e:98:6d:db:
0e:7d:f9:22:a3:ca:cb:12:b2:ed:eb:14:0c:b3:31:
59:02:17:6d:6a
I need to remove the 04 from the beginning of this and also remove the ':' from between the characters and print it like this, in a single line:
d6b6f298ff94d83c36ad5f8640aad15ae1875d559dad8b2bfc18e7bb477f9f9a62c6193a9e65624e5e986ddb0e7df922a3cacb12b2edeb140cb3315902176d6a
How can I do that using Windows commands?
quite straightforward:
#echo off
setlocal enabledelayedexpansion
set "first=true"
(for /f "eol=p delims=" %%a in (input.txt) do (
set "line=%%a"
if defined first (set "line=!line:~2!" & set "first=")
<nul set /p ".=!line::=!"
))>output.txt
Read the input file line by line.
Use a flag (first) to check for first line and remove the first two chars.
Remove the colons and
use <nul set /p to write without a line break.
Edit as it turned out in comments, your file has actually just one long line. This changes the way for processing to:
for /f %%a in (input.txt) do set "line=%%a"
set "line=%line:pub:04:=%"
set "line=%line::=%"
echo %line%
Note: variables can just hold a certain amount of data, so this apporach will fail, when the line exceeds this limit.
Your question is pretty confusing. You first say: "I have a text file having the string:", but the example data have six lines that could be taken as six strings, so at this point we have no idea of what the real data format is. Perhaps a single long line that you write here in six parts?
Next, you said "I need to remove the 04 from the beginning of this", but what happen if the data have not a 04 at the beginning? Perhaps you want to remove the first element even if it is not a 04?
In this way, we must assume several points in order to try to write a working solution.
The Batch file below read a file with several lines, remove the first line (even if it does not contain pub:), and remove the first colon-separated element (even if it is not 04):
#echo off
setlocal EnableDelayedExpansion
rem Read all lines, excepting the first one:
set "string="
for /F "skip=1" %%a in (input.txt) do set "string=!string!%%a"
rem Remove the first element:
set "string=%string:*:=%"
rem Show the rest, removing colons:
echo %string::=%
In this code there are other assumptions that are implicit in the way the commands work, like lines that does not contain spaces nor exclamation marks. Of course, if the real data file have a different format, this program will fail...

Batch script to grab lines with findstr without filepath

I've got a log file that monitors a large system including requests and acknowledgements. My objective is to be able to:
1. Loop through the script and get the lines where requests & their acknowledgements happen
2. Pull the entire lines of importance as strings and store them as variables for string modifying to output somewhere else.
Here's what I have so far:
#ECHO off
setlocal
setlocal enabledelayedexpansion
setlocal enableextensions
:: Lets get today's date, formatted the way the ABCD File is named
for /f "tokens=1-5 delims=/ " %%d in ("%date%") do set targetDate=%%f-%%d-%%e
:: Now we set the targetFile name
SET ABCDLogsFile=C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX*%targetDate%.log
::****Scrapped original approach*****
set "ackFoundCount=0"
set "reqFoundCount=0"
::Get lines with acks
for /f delims^=^ eol^= %%a in ('findstr /c:"\<ACK\>" "%ABCDLogsFile%"') do (
set /a "ackFoundCount+=1"
setlocal enabledelayedexpansion
for %%N in (!ackFoundCount!) do (
endlocal
set "ackFound%%N=%%a"
)
)
::Get lines with requests
for /f delims^=^ eol^= %%b in ('findstr /c:"ReqSingle" "%ABCDLogsFile%"') do (
set /a "reqFoundCount+=1"
setlocal enabledelayedexpansion
for %%N in (!reqFoundCount!) do (
endlocal
set "reqFound%%N=%%b"
)
)
setlocal enabledelayedexpansion
for /l %%N in (1,1,2 %reqFoundCount%) do echo REQ %%N FOUND= !reqFound%%N!
pause
for /l %%N in (1,1,2 %ackFoundCount%) do echo ACK %%N FOUND= !ackfound%%N!
endlocal
EDIT 2 dbenham
The roundabout way I was trying to accomplish this before was totally unnecessary.
Thanks to the questions and answer here:
'findstr' with multiple search results (BATCH)
I've got my script working similarly. However, I'm curious if its possible to get findstr output without the filepath at the beginning. I only need to substring out the timestamp in the log, which would always be the first 12 characters of each line (without the filepath). My output currently is prefixed with the path, and while I could get the path where the log would eventually be in production, it would be safer to try and do it another way. At the time that this script would eventually be run, there would only be 1 or 2 reqs and acks each, that is why I store all which are found. It's not necessary but I think it would be reassuring to see two if there are two. Here is what the output looks like for acks and reqs alike:
C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX 2015-04-01.log:2015-03-26 07:00:11,028 INFO etc...
I'm thinking that if I could strip the filepath off the start, then all I'd need to do to get just the timestamps of the events would be
for /l %%N in (1,1,1 %reqFoundCount%) do echo Req %%N occurred at: !reqFound%%N:~0,12! >> MorningAckChecks.txt
for /l %%N in (1,1,1 %ackFoundCount%) do echo ACK %%N occurred at: !ackfound%%N:~0,12! >> MorningAckChecks.txt
I suspect you could not get SKIP to work because you you were iterating the delimited list of line numbers with a FOR statement, which means the number is in a FOR variable. Problem is, you cannot include FOR variables or (delayed expansion) when specifying a SKIP value, or any other FOR option. The batch parser evaluates the FOR options before FOR variables are expanded, so it couldn't possibly work. Only normal expansion can be used when including a variable as part of FOR options.
But I don't understand why you think you need the line numbers at all. FINDSTR is already able to parse out the lines you want. Simply use FOR /F to iterate each matching line. For each line, define a variable containing the line content, and then use substring operations to parse out your desired values.
But I can offer an alternative that I think could make your life much easier. JREPL.BAT is a sophisticated regular expression text processor that could identify the lines and parse out and transform your desired values, all in one pass. JREPL.BAT is a hybrid JScript/batch script that runs natively on any Windows machine from XP onward.
If I knew what your input looked like, and what your desired output is, then I could probably knock up a simple solution using JREPL.BAT. Or you could read the extensive built in documentation and figure it out for yourself.
Documentation is accessed from the command line via jrepl /?. You might want to pipe the output through MORE so you get one screen of help at a time. But I never do because my command line console is configured with a large output buffer, so I can simply scroll up to see past output.
EDIT - In response to comment and updated question
Here are the relevant snippets of your code that are causing the problem.
SET ABCDLogsFile=C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX*%targetDate%.log
findstr /c:"\<ACK\>" "%ABCDLogsFile%"
findstr /c:"ReqSingle" "%ABCDLogsFile%
The issue is your ABCDLogsFile definition includes a wildcard, which causes FINDSTR to prefix each matching line with the full path to the file name where the match occurred.
I have a simple solution for you - Just change the definition of ABCDLogsFile as follows:
SET "ABCDLogsFile=C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX<%targetDate%.log"
Explanation
My solution relies on two undocumented features
1) Undocumented file mask wildcards.
< - Very similar to *
> - Very similar to ?
These symbols are normally used for redirection, so they must be either quoted or escaped if you want to use them as file mask wildcards.
We discuss the undocumented feature at DosTips - Dir undocumented wildcards. Sprinkled throughout the thread (and a link) are some example use cases.
I document my understanding of exactly how the non-standard wildcards work at http://www.dostips.com/forum/viewtopic.php?p=39420#p39420
2) FINDSTR works with the non-standard wildcards
FINDSTR will prefix each matching line with the file name (and possibly path) if any of the following conditions occur
The /M option is used
The /F option is used
Multiple input files are explicitly listed on the command line
Multiple input files are implied via a file mask with at least one * or ? wildcard on the command line
Your are getting the file path prefix because of the last trigger - the * in your file mask.
But you can use < instead to get the same result, except the non-standard wildcards do not trigger the file prefix in the output.
Problem solved :-)
I talk about this FINDSTR feature at http://www.dostips.com/forum/viewtopic.php?p=39464#p39464.
Some day I hope to update my What are the undocumented features and limitations of the Windows FINDSTR command? post with this tasty little tidbit.
This post has become a bit cluttered. It would be very helpful if you posted the lines of input that correspond to the output you are getting. If you can't do that then add this statement before your FOR. I am sure you will find that testReqSkip is blank.
echo.testReqSkip=%testReqSkip%

Removing some columns and rows from csv file via batch

I am trying to create a batch file that will edit a .csv and remove the first column, and any summary lines contained in the file. I am, however, fairly new to programming batch files, so I am not sure the best way to start this, and it would be great if you could include a basic explanation of how the code works so I can be self-sustaining in the future!
,Type,Date,Num,Name,Memo,Member,Clr,Split,Alias,Value,Balance
ABB - Egypt,,,,,,,,,,,
ElAin EL-Sokhna,,,,,,,,,,,
,Invoice,09-06-10,12005,ABB - EL-Sokhna,,Accounts Receivable,,Training Income,15000,,15000
,Invoice,09-14-11,12005,ABB - EL-Sokhna,“ElAin EL-Sokhna“ Trainer for OTS Application: First two weeks,Training Income,,Accounts,,150001,0
Total ElAin EL-Sokhna,,,,,,,,,241194,210400,301794
ABB - Egypt - Other,,,,,,,,,,,
There are various iterations of this file, as they come from a monthly report, I need to remove the first (empty) column, and any rows that look like ABB - Egypt,,,,,,,,,,, or Total ElAin EL-Sokhna,,,,,,,,,241194,210400,301794
So the output should be:
Type,Date,Num,Name,Memo,Member,Clr,Split,Alias,Value,Balance
Invoice,09-06-10,12005,ABB - EL-Sokhna,,Accounts,,Training Income,15000,,15000
Invoice,09-14-11,13002,ABB - EL-Sokhna,“ElAin EL-Sokhna“ Trainer for OTS Application: First two weeks,Training Income,,Accounts,,150001,0
Thanks for the input!
EDIT: It seems I wasn't clear enough in my OP (Sorry, first time here).
There are two processes that need to happen here, in every file the first column must be deleted, and any lines that are either title lines ABB - Egypt,,,,,,,,,,, or summary lines Total ElAin EL-Sokhna,,,,,,,,,241194,210400,301794 need to be removed.
All lines that need to be kept will be mostly filled in, such as ,Type,Date,Num,Name,Memo,Member,Clr,Split,Alias,Value,Balance or ,Invoice,09-06-10,12005,ABB - EL-Sokhna,,Accounts Receivable,,Training Income,15000,,15000 Notice that, as in the second line, it is possible for there to be some missing values in them, so doing a search for something like ",," will not work.
Batch is a terrible language for modifying text files. There are a great many special cases that require arcane knowledge to work around the problem. You may have a script that seems to do what you want, and then some wrinkle appears in your data, and the entire script may have to be redesigned.
With regard to your specific problem, it appears to me that you only want to preserve rows that begin with a comma, meaning the first column is empty. Of those remaining rows, you want to remove the first (empty) column.
Assuming none of the rows you want to keep have an empty value for the second column, then there is a really trivial solution:
#echo off
>"%~1.new" (for /f "delims=, tokens=*" %%A in ('findstr "^," %1') do echo %%A)
move /y "%~1.new" %1 >nul
The script expects the file to be passed as the first and only argument. So if your script is named "fixCSV.bat", and the file to be modified is "c:\test\file.csv", then you would use:
fixCSV "c:\test\file.csv"
The %1 expands to the value of the first argument, and %~1 is the same, except it also strips any enclosing quotes that may or may not be present.
The FINDSTR command reads the file and writes out only lines that begin with a comma. The FOR /F command iterates each line of output. The "delims=, tokens=*" options effectively strip all leading commas from each line, and the result is in variable %%A, which is then ECHOed. The entire construct is enclosed in parentheses and stdout is redirected to a temporary file. Finally, the temporary file is moved over top of the original file, thus replacing it.
If the 2nd column may be empty, then the result will be corrupted because it removes all leading commas (both columns 1 and 2 in this case). The script must be more complicated to compensate. You would need to set a variable and then use delayed expansion to get the sub-string, skipping the first character. But delayed expansion will corrupt expansion of the %%A variable if it contains the ! character. So delayed expansion must be toggled on and off. You are beginning to see what I mean by lots of special cases.
#echo off
setlocal disableDelayedExpansion
>"%~1.new" (
for /f "delims=" %%A in ('findstr "^," %1') do (
set "ln=%%A"
setlocal enableDelayedExpansion
echo !ln:~1!
endlocal
)
)
move /y "%~1.new" %1 >nul
As the batch scripts become more complicated, they become slower and slower. It may not be an issue for most files, but if the file is really large (say hundreds of megabytes) then it can become an issue.
I almost never use pure batch to modify text files anymore. Instead, I use a hybrid JScript/batch utility that I wrote called JREPL.BAT. The utility is pure script that runs natively on any Windows machine from XP onward. JREPL.BAT is able to efficiently modify text files using regular expression replacement. Regular expressions can appear to be mysterious, but they are well worth the investment in learning.
Assuming you have JREPL.BAT somewhere within your PATH, then the following command is all that you would need:
jrepl "^,(.*)" "$1" /jmatch /f "yourFile.csv" /o -
The /F option specifies the file to read.
The /O option with value of - specifies that the output should replace the original file.
The /JMATCH option specifies that each replacement value is written out to a new line. All other text is dropped.
The first argument is the search expression. It matches any line that begins with a comma, and everything after that is captured in a variable named $1.
The second argument specifies the replacement value, which is simply the captured value in variable $1.
A way will be to define all your rules in a variable which will be used against
findstr. The rules must be defined like this :
/c:"String which exclude the line" /c:"Another string which exclude the Line" /c: "etc.."
This rules must be exact (That they can't be found in a line who must stay).
For the empty first colonne you can use a substitution the way i made it in the code with
,Type=Type
,Invoice=Invoice
Test.bat :
#echo off&cls
setlocal enabledelayedexpansion
Rem The rules
set $String_To_Search=/c:"ABB - Egypt," /c:"Total ElAin El-Sokhna," /c:"ElAin EL-Sokhna," /c:"ABB - Egypt - Other,"
for /f "delims=" %%a in (test.csv) do (
set $line=%%a
Rem the substitutions for the first Column
set $Line=!$Line:,Type=Type!
set $line=!$Line:,Invoice=Invoice!
Rem the test and the ouput if nothing was found
echo !$Line! | findstr /i %$String_To_Search% >nul || echo !$Line!
))>Output.csv
I used a file test.csv for my test.
The ouput is redirected to Output.csv
Perhaps is this what you want?
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%a in (input.csv) do (
set "line=%%a"
if "!line:~0,1!" equ "," echo !line:~1!
)
When a problem is not enough explained we can only guess the missing details. In this case, I assumed that you just want the lines that start with comma, deleting it. The output is the same as your output example...
EDIT: Output example added
Type,Date,Num,Name,Memo,Member,Clr,Split,Alias,Value,Balance
Invoice,09-06-10,12005,ABB - EL-Sokhna,,Accounts Receivable,,Training Income,15000,,15000
Invoice,09-14-11,12005,ABB - EL-Sokhna,“ElAin EL-Sokhna“ Trainer for OTS Application: First two weeks,Training Income,,Accounts,,150001,0
I would start here to learn this: How can you find and replace text in a file using the Windows command-line environment?
It covers many details of substitution from Windows command line and many ways to do it, some requiring only what's built into Windows, and some requiring other downloadable software.
Magoo is right, more criteria is needed, but there might be enough information in the linked page for you to get past the main hurdles.
#ECHO OFF
SETLOCAL
(FOR /f "tokens=*delims=," %%a IN ('findstr /b /l "," q28079306.txt') DO ECHO %%a)>newfile.txt
GOTO :EOF
I used a file named q28079306.txt containing your data for my testing.
Produces newfile.txt

batch file changing double quote

Having trouble running a batch file.
SET startIN="D:\Documents and Settings\%USERNAME%\Desktop\DataXfer Helper\StartFolder"
SET collection="D:\Documents and Settings\%USERNAME%\Desktop\DataXfer Helper\StartFolder\*.zip"
FOR /F %%G IN (‘dir /b %collection%\*.zip’) DO “C:\Program Files\Winzip\wzunzip” –E %startIN%\%%G %startIN%
When I type the line at the command prompt - it works fine (the only difference is when typed at the command prompt I use %G instead of %%G).
So, the environement variables are being created properly - but when I run the batch, the single quotes and the hyphen before the E are being turned into other characters (can't identify what they are).
So, any ideas why running the batch would change the characters?
Thank you.
There are a couple of problems:
The symbols in your FOR line are not supported ASCII chars. Retype the ', ", and - in the command line to correct them.
The string expansion is going to include the quotes you set in the path above. For example, %startIN%\%%G will expand to "D:\Documents and Settings\%USERNAME%\Desktop\DataXfer Helper\StartFolder"\MyFile.zip. When dealing with paths, make sure your logic is aware of quotes so they don't get trapped in the middle of the result.
Try updating your script to this:
REM Remove the quotes from the path.
REM Quotes will be added once we know the full path.
SET startIN=D:\Documents and Settings\%USERNAME%\Desktop\DataXfer Helper\StartFolder
REM Quote here because we know the full path.
SET collection="%startIN%\*.zip"
REM Update FOR loop to include parsing options and properly quote output.
REM Also update invalid ASCII chars.
FOR /F "usebackq tokens=* delims=" %%G IN (`dir /b %collection%`) DO "C:\Program Files\Winzip\wzunzip" -E "%startIN%\%%G" "%startIN%"

Resources