String replace troubles - string

I am trying to read a file and remove the forward slash character (/) from each line. Here's what I have:
for /F "tokens=*" %%A in (%BRANCH_OUT%) do SET THIS_BRANCH=%%A && ECHO %THIS_BRANCH:/=%
It works great, but the echo only displays the last line in the file for each line. So, a file containing:
Dir1/
Dir2/
Dir3/
Would be read and output as
Dir3
Dir3
Dir3
Any suggestions on how to solve this?

If you want to assign and then use a variable in a for loop, you must enable and used delayed expansion. For instance, given the following:
c:\>#for %i in (a b c d) do #set _x=%i && #echo %_x%
d
d
d
d
This echos the d character 4 times, like you observed. If you have delayed expansion enabled and you change it like this, it echos each of the 4 letters instead of d 4 times.
c:\>#for %i in (a b c d) do #set _x=%i && #echo !_x!
a
b
c
d
So, in your batch file, you need to add setlocal ENABLEDELAYEDEXPANSION at the beginning of the batch file, and endlocal at the end. This makes sure that you can use the !_x! notation to get the delayed expansion.

Related

Batch script - split by two or more spaces

I have a large string that looks like this
aa bb c d f eeeee ffff
I am not sure of the number of spaces that would come along with the string. The next time, string might have five spaces between aa and bb ansd so on...
aa bb c f eee ff
Is there a way I can split on two or more spaces (variable number of spaces) using delims in batch script?I always want the second token no matter how any spaces are there between first and second tokens.
PS : Edit
I want the second token (by token I mean the token obtained after splitting by exactly two or more spaces). My token itself can contain a single space. Example: a b c d.
In this want to extract b.
Another example: a b b c d .
In this I want to extract b b.
(Collected from various comments: Tokens are delimited by two or more spaces; You need the second token; Every token may or may not have single spaces)
I commented every step and added an echo to show progress.
#echo off
setlocal
set "string=ads ads d b c dsad ds ads"
echo 1: "%string%"
REM remove first token (delimited by ecactly two spaces):
set "string=%string:* =%"
echo 2: "%string%"
REM remove leading spaces:
for /f "tokens=*" %%a in ("%string%") do set "string=%%a"
echo 3: "%string%"
REM remove third and next tokens (delimited by two or more spaces)
set string=%string: =&REM %
echo 4: "%string%"
Only change to my answer to your previous question is the for to remove leading spaces
Notice for future readers:
This answer was posted before OP added the significant text I always want the second token no matter how any spaces are there between first and second tokens.
Please read the original question before voting/commenting
No.
delims means that tokens are separated by any sequence of any of the defined delimiter characters.
Hence your example string would be processed as 7 separate tokens.
If you were to tell us what you are attempting to do,it may help. The approach taken often depends on the desired results.
Probably this is associated with https://stackoverflow.com/a/48808982/2128947 to which you have yet to respond.
This is how I implemented this incase anyone is interested.
#echo off
echo.
set "string=Admin State State Type Interface Name"
echo Parse "%string%"
REM: Parse string delimited by more than one space
for %%R in ("%string: =" "%") do (
REM: Filter empty
if not "%%~R" == "" (
REM: Trim leading space
for /f "tokens=*" %%a in ("%%~R") do set "part=%%a"
call echo - "%%part%%"
)
)
echo.
goto :eof
Output:
Parse "Admin State State Type Interface Name"
- "Admin State"
- "State"
- "Type"
- "Interface Name"
This is the way I would do it:
#echo off
setlocal
set "string=ads ads d b c dsad ds ads"
set "tok1=%string: =" & if not defined tok2 set "tok2=%"
for /F "tokens=*" %%a in ("%tok2%") do set "tok2=%%a"
echo "%tok2%"
If you want to understand the method used, remove the #echo off line and carefully review the executed code...

batch code to test if script contains anything other than Letters and Numbers

I was wondering if it is possible to test a variable to see if it contains anything other than Letters and numbers? I need to have this in order to limit username specs. I have a kind of example script below.
:top
echo enter a name
set /p name=">"
If contains (Anything other than letters/numbers/dashes) echo Invalid Name. & goto top
echo thank you!
pause
Thanks everyone!
Edit: I would think this is probably a duplicate, however I do not know what to search for to find other posts... Whenever I searched anything related to my question it brought up find and replace in text files or something else unrelated. If anyone can find a duplicate please let me know and I will close this question. Thank you.
This work for the majority of ascii characters. It may have some caveats.
#echo off
set /p "name=Enter a name>"
set "test=%name%"
FOR %%G IN ( a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 ) do (
IF DEFINED test call set "test=%%test:%%G=%%"
)
IF DEFINED test (
echo Invalid characters in username:"%test%"
) else (
echo Good Username: "%name%"
)
pause
This allows only letters, numbers, and dashes:
#echo off & setlocal
:top
set /P "name="Enter a name: "
setlocal enabledelayedexpansion
echo(!name!| findstr /i "[^a-z0-9-]" >NUL && (
endlocal
set /P "=Invalid name. " <NUL
goto top
)
endlocal
echo Thank you %name%!
pause

Combining substrings of different lines into a single line in batch for loop

I have a .txt file with some data in it, where "BARREL-5, BODY-3" etc are what is being measured, the decimal after the "V" is the measured value, and the date (sans the exact time) is being used to identify which sample the measurement belongs to, as such
4491 316 SS,BARREL-5,V,1.393,5/7/2015 7:47:05 AM,0,,,,13,...
4491 316 SS,BARREL-5,V,1.3865,2/17/2016 11:26:12 AM,0,,,,13,...
4491 316 SS,BODY-3,V,1.256,5/6/2015 6:45:42 PM,0,,,,13,...
4491 316 SS,BODY-3,V,1.2565,5/7/2015 7:46:16 AM,0,,,,13,...
4491 316 SS,BODY-3,V,1.246,2/17/2016 11:24:18 AM,0,,,,13,...
This data is exported from a (really obsolete) program in .txt format only every time we take sample measurements for a batch of parts. The data needs to be viewable in excel to quickly determine if the batch of parts is in tolerance or not. The problem with changing an extension and going with it is that a full line of data is as follows:
4491 316 SS,BARREL-5,V,1.393,5/7/2015 7:47:05 AM,0,,,,13,Blow Pattern=1-1-1,Die Set=FN3,Forge=Erie,Heat #=E150058,Job #=I2928,Lube Type=Hydraforge,Operator=Paul & ,Revision=C,Run Temperature=2250,Shift=2nd,Shim bottom Die=X,Shim Top Die=X,Shim Trimmer=X,C
This comes out really messy in excel, and the number of columns can vary +1 sometimes (it adds a column following the 0 in 0,,,, if that 0 is instead a 1).
My desired output, in txt format, would look something like this:
Project Number: 4491,,,, Material: 316 SS
,5/7/2015,2/17/2016,5/6/2015
BARREL-5,1.393,1.3865,NA
BODY-3,1.256,1.2565,1.246
Right now I loop through all the lines, extract all the dates, remove any duplicates (down to a list of each unique date), and then turn those into a string in the csv file as such ,date1,date2,date3,etc.
I then loop through the data file again and put the variable name down on a new line, checking first to see if it is repeated and if so, not echoing that variable name. I am using the following for loop to do this (filePath is a file path and project number combined, with the file extension or name-addition to be added on as needed):
for /f "tokens=1 delims=," %%a IN (%filePath%.txt) DO (
set varname=%%a%
find "!varname!" %filePath%Excel.csv
if !errorlevel!==1 (echo !varname! >> %filePath%Excel.csv)
)
My current output essentially looks something like this:
Project Number: 4491,,,, Material: 316 SS
,5/7/2015,2/17/2016,5/6/2015
BARREL-5,
BODY-3,
As you can see, I need to put the actual measured values in their proper locations. Is there any easy way to do this in batch? The code must be easily run by anyone, on any computer (Win 7 and XP). The data files are unlikely to change anytime soon, so the program doesn't need to be very robust. I am also limited by the fact that I tried using Powershell but discovered that I am not allowed to run any scripts on any of the computers...
The approach I hesitate to dig into would be something along the lines of creating a list of the line numbers for each line which switches to a new measurement name, then running another loop through the file and printing all the values on the same line, breaking them up based on the line count. The lines of variables would then be concatenated to the proper lines in the csv file.
Thanks for any help. I have edited this to include more relevant examples and details.
Your description is confusing and you did not shown what is the desired output, so there is no way to try to write a solution to your problem... However, your partial requirements can be obtained via a Batch file in a very simple way:
#echo off
setlocal EnableDelayedExpansion
set "dates="
for /F "tokens=1-3 delims=," %%a in (test.txt) do (
rem Get a list of unique dates:
set "dates=!dates:%%c,=!%%c,"
rem Take the values of the variables
set "var[%%a]=!var[%%a]!,%%b"
)
rem Show the results
echo Dates: %dates:~1,-1%
echo/
echo Variables:
for /F "tokens=2* delims=[]=" %%a in ('set var[') do echo %%a%%b
Using this data as input file:
varname1,valueA,date1
varname1,valueB,date2
varname1,valueC,date3
varname2,valueD,date1
varname2,valueE,date2
varname2,valueF,date3
... this is the output:
Dates: date1,date2,date3
Variables:
varname1,valueA,valueB,valueC
varname2,valueD,valueE,valueF
EDIT: Code modified to fulfill the new specifications
#echo off
setlocal EnableDelayedExpansion
set "max=0"
set "dates=,"
for /F "tokens=1-4,6,7 delims=, " %%a in (test.txt) do (
rem Get header data
set "project=%%a" & set "material=%%b %%c"
rem Get a list of unique dates
if "!dates:%%f=!" equ "!dates!" set "dates=!dates!%%f,"
rem Take the values of the variables
set "var[%%d]=!var[%%d]!,%%e"
rem Get data for variable equalization
set "data=%%d"
for /F %%D in ("!data:-=_!") do (
set /A "len[%%D]+=1"
if !len[%%D]! gtr !max! set "max=!len[%%D]!"
)
)
rem Equalize variables
set /A max-=1
for /F "tokens=2,3 delims=[]=" %%i in ('set len[') do (
set "data=%%i"
for /F %%D in ("!data:_=-!") do for /L %%I in (%%j,1,%max%) do (
set "var[%%D]=!var[%%D]!,NA"
)
)
rem Show the results
(
echo Project Number: %project%,,,, Material: %material%
echo %dates:~0,-1%
for /F "tokens=2* delims=[]=" %%a in ('set var[') do echo %%a%%b
) > output.txt
The output generated by this program is exactly the same specified in the question...
An easy way by 2 command lines to solve your question, see screenshot at bottom.
:: Extract all dates and get unqiue
msr -p your-source.txt -t "^.*?,(\d+/\d+/\d+)\s+(\d+:\d+:\d+).*" -o "$1" -PAC | nin nul -uPAC | msr -S -t "(\S+)\s+" -o ",$1" -PAC >> result.csv
:: Extract column2 like "BARREL-5" -> Auto classify -> Extract values like "1.393" -> Add "NA" if lack columns
for /f "tokens=*" %%a in ('nin source.txt nul "^[^,]+,([^,]+)" -u -PAC') do #msr -p source.txt -t ".*?,%%a,V,(\d+\.\d+),.*" -o "$1" -PAC | msr -S -t "\s+(\S+)" -o ",$1" -PAC | msr -t "^\d+\.?\d*,\d+\.?\d*$" -o "$0,NA" -aPAC| msr -t ".+" -o "%%a,$0" -PAC >> result.csv
But I don't know how you first line come out: Project Number: 4491,,,, Material: 316 SS
The above uses 2 common single exe tool (no dependencies): msr.exe (Match/Search/Replace) + nin.exe (Not-In-latter: get difference/intersection) in my open project https://github.com/qualiu/msr tools directory.
Use msr-Win32.exe and nin-Win32.exe if you're on a 32-bit Windows.

How to add empty space using batch script?

Is there any way to loop a text file which will add a EMPTY SPACE in front of each line?
commit.txt
commit c9bee
Merge: 7db
Author: TOM
Date: Fri Mar 13
Author: TIM
output.txt
commit c9bee
Merge: 7db
Author: TOM
Date: Fri Mar 13
Author: TIM
Here's one solution:
for /f "delims=" %i in (file) do #echo %i
Note that you must double the percents if you use this in a script (as opposed to interactive usage).
try this. This "overwrites" the original file.If you want to keep the name as output.txt just comment out the call to Overwriteoriginal
#echo off
REM makes sure the user passed in a file name
if [%1]==[] (
echo Must pass in a file name
) else (
Call:AddSpaceToEveryLine %1
Call:OverwriteOriginal %1
echo processed %1
)
GoTo:EOF
:OverwriteOriginal
REM overwrites original file with spaced file
del %1
rename output.txt %1
GoTo:EOF
:AddSpaceToEveryLine
REM there is actually one space after the equals sign
set space=
for /f "tokens=*" %%a in (%1) do (
echo %space%%%a >> output.txt
)
GoTo:EOF
-Editing here to mention escaping the space is not required, you can use ECHO 1 to get a (space)1.
Try escaping the space using ^
For example:
C:\Scripts>echo ^ string
string
C:\Scripts>echo string
string
-edit, this is what happens when you rush and don't read the question fully!
Try this:
C:\Scripts>for /f %a in (input.txt) do echo ^ %a
C:\Scripts>echo test1
test1
C:\Scripts>echo test2
test2
It can be done very easily and you don't need a for loop for it. Just declare a variable and and at the end of of your code just to do echo with the declared variable few times to your output file. In this case, I am sending to a file called c:\sample.txt. Here is an example:
#echo off
set blank=
:: Your main code goes here
echo. %blank% >> c:\sample.txt
echo. %blank% >> c:\sample.txt
echo. %blank% >> c:\sample.txt
echo. Author: TIM >> c:\sample.txt

batch/txt: How to replace a substring-matched data block with modified input from a file

A user defined input file has to be integrated into the entries of pre-set output file,
changing the data at a given block [A-Z] and index [1-75] position.
The input file structure with wildcards for variable parts:
* 00asr[1-75] 00asr*
b -v -o 00asr34 00asr34.hkx (example)
b -v 00asr35 00asr35.hkx (example)
Output file as above but with multiple blocks [A-Z]asr[1-75]:
* Aasr[1-75] Aasr*
* Basr[1-75] Basr*
...
* Zasr[1-75] Zasr*
The user has to pick a given letter A-Z to determine parts of the string and the block to replace information in.
Then we can replace the %input% substrings 00asr with %block%asr; they will then match given substrings in the %output%:
* 00asr[1-75] 00asr* >> * Zasr[1-75] Zasr* in the case of Z.
#ECHO OFF
ECHO INPUT FILE:
ECHO %1
SET INTEXT=%1
ECHO.
SET /P "LETTER=Letter? "
SET "REPLACE=%LETTER%asr"
SET TMP=tmp.txt
setlocal enabledelayedexpansion
FOR /F "tokens=1,* delims=¶" %%A IN ( '"TYPE %INTEXT%"') DO (
SET string1=%%A
SET modified=!string1:00asr=%REPLACE%!
echo !modified! >> %TMP%
)
PAUSE
I adapted this code. Looks like good code to me, but I'm like a blind man.
Now either the %TMP%s first-line [1-75] is required to determine whether there is any offset in the block
or the strings have to be compared, overwriting the line containing substring * Zasr[1-75] Zasr* with the same one from %TMP%;
or in the case of offset skipping a given amount of lines in %output% before overwriting the lines.
I'm not sure which option would be easier to implement or quicker to execute,
since I'm entirely failing at doing this.
The whole method should work something like this:
Input File
o <parameters> 00asr3 00asr3.hkx
o <parameters> 00asr4 00asr4.hkx
o <parameters> 00asr5 00asr5.hkx
User Input
Q
OUTPUT BEFORE
...
p Oasr75 Oasr75.hkx
p Qasr1 Qasr1.hkx
p Qasr2 Qasr2.hkx
p Qasr3 Qasr3.hkx
p Qasr4 Qasr4.hkx
p Qasr5 Qasr5.hkx
p Qasr6 Qasr6.hkx
....
OUTPUT AFTER
...
p Oasr75 Oasr75.hkx
p Qasr1 Qasr1.hkx
p Qasr2 Qasr2.hkx
o <parameters> Qasr3 Qasr3.hkx
o <parameters> Qasr4 Qasr4.hkx
o <parameters> Qasr5 Qasr5.hkx
p Qasr6 Qasr6.hkx
....
I managed to write the file renaming parts just fine; but this... I don't even.
I have been looking at various articles but due to not actually knowing any batch I'm not getting ahead with this.
1 Was very helpful, but I outright fail to compare strings correctly and can't seem to manage to assign them to variables.
Any help is appreciated. I might even understand what I'm doing wrong (which currently is most things).
I've solved it by myself.
Here's a shortened version of the script.
Cleaning input somewhat, changing the token in tmp, getting target parameters,
removing old target strings from file, merging files, deleting temps.
I'm confident this code isn't very good either way so further explanation seems unnecessary.
#ECHO OFF
SET _PACK=%1
SET "PATH=%~dp0"
SET "_LIST=in.txt"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "_ERROR=0"
:USERINPUT
IF %_ERROR%==1 (
ECHO INVALID INPUT: string too long.
SET "_ERROR=0"
)
IF %_ERROR%==2 (
ECHO INVALID INPUT: non-letter.
SET "_ERROR=0"
)
SET /P "LETTER=ENTER NEW BLOCK LETTER A-Z: "
ECHO "%LETTER%" SELECTED
IF NOT "%LETTER:~1,1%"=="" (
SET "_ERROR=1"
GOTO USERINPUT
)
if "%LETTER%" lss "A" (
SET "_ERROR=2"
GOTO USERINPUT
)
if "%LETTER%" gtr "Z" (
SET "_ERROR=2"
GOTO USERINPUT
)
SET "_STRING=%LETTER%asr"
' renaming files here
SET TMP=asr.tmp
DEL %TMP%
SET "_COUNT=0"
FOR /F "tokens=1,* delims=¶" %%A IN ( '"TYPE %_PACK%"') DO (
SET _LINE=%%A
SET _NEWLINE=!_LINE:0asr=%_STRING%!
ECHO !_NEWLINE!>> %TMP%
CALL SET /A _COUNT=_COUNT+1
)
ECHO NUMBER OF INPUT LINES: !_COUNT!
SET /P _OFFSET=< %TMP%
CALL SET _OFFSET=%%_OFFSET:*asr=%%
CALL SET _OFFSET=%%_OFFSET:~0, 2%%
CALL SET _OFFSET=%_OFFSET: =%
ECHO OFFSET: %_OFFSET%.
SET /A _END=_COUNT+_OFFSET-1
COPY /Y in.txt in.tmp
FOR /L %%X IN (%_OFFSET%, 1, %_END%) DO (
SET "_SEARCH=%_STRING%%%X "
ECHO DELETING OLD STRING : !_SEARCH!
FINDSTR /V /C:"!_SEARCH!" %_PACK% > in.tmp
del in.txt
ren "in.tmp" "in.txt"
)
TYPE %TMP%>> in.txt
DEL %TMP%
PAUSE
DEL %1
EXIT

Resources