Add space character to the end of a particular line - vbscript

I want to write a vbscript or batch file to run over almost a hundred files (in the same directory) and do the following:
For each line that starts with the string "component " (there is a space after component)
I want to add at the end of that line a space. Other lines won't be affected.
For example:
this is line one
component this is line two
this is line three
will change to:
this is line one
component this is line two (<=space)
this is line three
(There is only one space after the word "two".)

#echo off
for /f "tokens=1,* delims= " %%a in (file.txt) do (
if "%%a"=="component" (
echo %%a %%b >>temp.txt
) else (
echo %%a %%b>>temp.txt
)
)
del file.txt /f /s /q
ren temp.txt file.txt

#Echo OFF
:: By Elektro H#cker
Set "File=Test.txt"
Set "Word=Component"
FOR /F "Usebackq Tokens=* Delims=" %%# IN ("%FILE%") DO (
Echo "%%#"| FINDSTR /I "^\"%WORD%.*\"" >NUL && (
Echo %%# >>".\Output.txt"
) || (
Echo %%#>>".\Output.txt"
)
)
Pause&Exit

In VBScript you could do that with a regular expression:
in = "input.txt"
out = "output.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
text = fso.OpenTextFile(in).ReadAll
text = Replace(text, vbCrLf, vbLf) ' remove CR b/c it interferes with
' multiline matches
Set re = New RegExp
re.Pattern = "^(component .*)$"
re.MultiLine = True
re.Global = True
text = re.Replace(text, "$1 ")
text = Replace(text, vbLf, vbCrLf) ' restore CRLF
fso.OpenTextFile(out, 2, True).Write(text)
fso.DeleteFile in
fso.MoveFile out, in

Related

Batch find and replacing text between parentheses

I need to replace the text after HOST = with a user input in my text file with pure batch.
The name VM-TEST is not always the same and can change because this will be used in multiple files.
I'm stuck here.
Text example:
(ADDRESS = (PROTOCOL = TCP)(HOST = VM-TEST)(PORT = 1521))
All I got is this:
#echo off &setlocal
set "search=host ="
set "replace=HOST = test"
set "textfile=Input.txt"
set "newfile=Output.txt"
(for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
))>"%newfile%"
del %textfile%
rename %newfile% %textfile%
Hey :) I've built a little script that should do the job.
It splits up the properties on the opening bracket first, so you can then check if it matches the property you are looking for. This is done using findstr /r and therefore makes it possible for you to write simple regular expressions as search string. Your name "VM-TEST" is represented as ".*" in the regex, so it can be any string.
#echo off & setlocal
set "search=host = .*)"
set "replace=HOST = test)"
set "textfile=in.txt"
set "newfile=out.txt"
del "%newfile%" 2>nul
for /f "usebackq delims=" %%L in ("%textfile%") do (
call :replaceProperty "%%~L"
)
del "%textfile%"
rename "%newfile%" "%textfile%"
exit
:replaceProperty
set "_remainingLine=%~1"
set "_outputLine="
:replaceProperty_while
if "%_remainingLine%"=="" goto break
if "%_remainingLine:~0,1%"=="(" (
rem this needs to be checked additionally as for /f skips empty tokens
set "_outputLine=%_outputLine%("
set "_remainingLine=%_remainingLine:~1%"
goto replaceProperty_while
)
for /F "tokens=1* delims=(" %%q in ("%_remainingLine%") do (
echo:%%q|findstr /i /r /c:"^%search%$">nul
if errorlevel 1 (
set "_outputLine=%_outputLine%%%q"
) else (
set "_outputLine=%_outputLine%%replace%"
)
if "%%r"=="" (
goto break
) else (
set "_remainingLine=(%%r"
)
)
goto replaceProperty_while
:break
rem Finished processing the line. Write output and exit subroutine.
rem This can't be done in the if-block because the output line will contain brackets.
echo:%_outputLine%>>"%newfile%"
exit /b
This is a sample file I used for testing:
(ADDRESS = (PROTOCOL = TCP)(HOST = VM-TEST)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = Something_else)(PORT = 1521))
this line won't get modified
(this works as well but
trailing brackets will get lost though (
((some other stuff = (text) ))
((HOST = VM-TEST)(PORT = 1521)(PROTOCOL = TCP))
Edit #1,2: Updated code for leading whitespace support and performance improvements.
Edit #3: I assume that every line in your file contains at least one space, but if you want that empty lines don't get lost, you can replace the first for /f "usebackq ... loop with this one:
for /f "tokens=1* delims=:" %%K in ('findstr /n /r "^" "%textfile%"') do (
call :replaceProperty "%%~L"
)
You could try the following script:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=D:\Target" & rem // (path to target directory)
set "_IFILE=Input.txt" & rem // (name of input file)
set "_OFILE=Output.txt" & rem // (name of output file)
set "_SEARCH=HOST" & rem // (keyword to search for)
set /P _REPLAC="Enter new HOST value: " & rem // (replacement value)
rem // Gather horizontal tabulator (TAB) character:
for /F "delims=" %%T in ('forfiles /P "%~dp0." /M "%~nx0" /C "cmd /C echo/0x09"') do set "_TAB=%%T"
rem // Write to output file:
> "%_ROOT%\%_OFILE%" (
rem /* Read from input file line by line, precede each line with line number + `:`
rem in order not to appear empty to `for /F` and therefore not to be skipped: */
for /F "delims=" %%L in ('findstr /N "^" "%_ROOT%\%_IFILE%"') do (
rem // Store current line, reset line buffer:
set "LINE=%%L" & set "COLL=("
rem // Toggle delayed expansion to avoid trouble with `!`:
setlocal EnableDelayedExpansion
rem // Remove temporary line number + `:` prefix:
set "LINE=!LINE:*:=!"
rem // Skip processing of an empty line:
if defined LINE (
rem // Skip processing of a line that contains `*`, `?`, `<`, `>`:
if "!LINE!"=="!LINE:**=!" if "!LINE!"=="!LINE:*?=!" if "!LINE!"=="!LINE:*<=!" if "!LINE!"=="!LINE:*>=!" (
rem // Temporarily double `"`:
set "LINE=!LINE:"=""!^"
rem // Split line at every `(` and loop through the items:
for %%I in ("!LINE:(=" "!") do (
endlocal
rem // Store current item:
set "ITEM=%%~I"
rem // Split item into keyword and remainder:
for /F "tokens=1* delims==%_TAB% " %%G in ("%%~I") do (
rem // Check whether keyword matches:
if /I "%%G"=="%_SEARCH%" (
rem // Split off `)` and everything behind from remainder:
set "REST=%%H"
setlocal EnableDelayedExpansion
for /F "tokens=1* delims=)" %%E in ("!REST:)=)(!") do (
endlocal
rem // Rebuild new item with replacement value:
set "ITEM=%%G = %_REPLAC%)%%F"
setlocal EnableDelayedExpansion
)
endlocal
)
)
setlocal EnableDelayedExpansion
rem // Revert doubling `"`:
if defined ITEM set "ITEM=!ITEM:""="!^"
rem /* Append item to line buffer;
rem transport result beyond `endlocal`: */
if defined ITEM set "ITEM=!ITEM:(=!"
for /F "delims=" %%K in ("!COLL!(!ITEM!") do (
endlocal
set "COLL=%%K"
setlocal EnableDelayedExpansion
)
)
set "LINE=!COLL:~2!"
)
)
rem // Return resulting line:
echo(!LINE!
endlocal
)
)
endlocal
exit /B
The following restrictions apply:
the keyword to search for must not contain =, SPACE, TAB, (, );
the given keyword to search (like HOST) is treated case-insensitively (to change that, remove the /I option from if /I "%%G"=="%_SEARCH%");
lines that contain the keyword to search (like HOST) must not contain any of the characters *, ?, <, >; if they do, the desired replacement is not performed;
the original sequence of white-spaces around the =-sign in the replaced string portion (like HOST = VM-TEST) is not maintained, it always is the keyword + SPACE + = + SPACE + the replacement value;

Echo specified lines from a text file

This might be an XY question, but I am trying to echo various lines from a text file.
#setlocal enableextensions enabledelayedexpansion
#echo off
set /a "line = 0"
for /f "tokens=* delims= " %%a in (file.txt) do (
set /a "line = line+1"
if !line!==18 set thing1=%%a
if !line!==19 set thing2=%%a
if !line!==20 set thing3=%%a
)
endlocal & set thing1=%thing1% & set thing2=%thing2% & set thing3=%thing3%
echo:
echo %thing1%
echo %thing2%
echo %thing3%
pause
This works well and is neat compared to others I found so I was tiring to to make it more adaptable. I can make the line numbers variable, but what if I wanted four lines, or a range of lines? So I tried to make a for loop.
List all the lines:
(
echo #setlocal enableextensions enabledelayedexpansion
echo #echo off
echo set /a "line = 0"
echo for /f "tokens=* delims= " %%a in (file.txt^) do (
echo set /a "line = line+1"
)>>test.bat
for /l %%m in (1,1,10) do (
echo if !line!==%%m set thing%%m=%%%%a
)>>test.bat
echo )>>test.bat
echo endlocal ^& )>>test.bat
for /l %%m in (1,1,10) do (
echo set thing%%m^=%%thing%%%%m ^&
)>>test.bat
Then I could echo %thing(anynumber%) as I wished.
This runs into problems when the for loop list need to be on the same line:
endlocal & set thing1=%thing1% & set thing2=%thing2% & set thing3=%thing3%
Instead it outputs:
endlocal &
set thing1=%thing%1 &
set thing2=%thing%2 &
set thing3=%thing%3 &
etc...
I know prompt $H can backspace, but I think that is a dead end for what I am trying here. I can't find much on reverse line feed online. Also it adds an ampersand to the final %%thing%% in the list.
Sample file.txt
This is line one
This is line two
This is line three
This is line four
This is line five
This is line six
This is line seven
This is line eight
This is line nine
This is line ten
Maybe findstr is the way to go about this. I found this and edited it to suit what I was trying to do:
:start
cls
set /p "line= Which lines?"
for /f "tokens=* delims=[] " %%a in ('type file.txt^|find /v /n ""') do (
echo/%%a|findstr /l /b "%line%" >nul && echo/%%a
)
pause
goto :start
But with an input of 1 it will echo every instance beginning with "1" i.e. 1,11,12,13 etc. This seems to be nearly there. I've tried various switches from the findstr /?, but can't figure it out. If it could do input ranges too, so input line 1-5,7,12-15 would echo them 10 lines.
This should do (although not with ranges):
#echo off
setlocal
set lines=1,5,6,8
(for %%a in (%lines%) do echo %%a:)>lines.txt
for /f "tokens=1,* delims=:" %%a in ('type file.txt^|findstr /n "^"^|findstr /bg:lines.txt') do echo/%%b
del lines.txt
The first for loop builds a temporary file for findstr /g (see findstr /? for details).
The second one adds line numbers, looks them up in the file and prints the original line if the line number is in the file.
The numbers in %lines% can be delimited by any standard delimiters (TABs, SPACEs, Commas and even = (not recommended - stay with spaces and/or commas)
To expand to Ranges 5-10, you'd need to parse %lines% with some more code (hard to make that fool-proof) and "translate" to single line numbers to write into lines.txt
(We could also expand %lines% to a REGEX search string or findstr, avoiding a temporary file, but it's much easier to understand and maintain this way)
Edit: implemented a simple "range extension" (without checking for plausability):
#echo off
setlocal
set "lines=1,4-6,9"
(for %%a in (%lines%) do (
echo %%a|find "-" >nul && call :range %%a || echo/%%a:
))>lines.txt
echo lines %lines% are:
for /f "tokens=1,* delims=:" %%a in ('type file.txt^|findstr /n "^"^|findstr /bg:lines.txt') do echo/%%b
del lines.txt
goto :eof
:range
for /f "tokens=1,2 delims=-" %%b in ("%1") do (
for /l %%i in (%%b,1,%%c) do echo %%i:
)
goto :eof
Output (with your sample input file):
lines 1,4-6,9 are:
This is line one
This is line four
This is line five
This is line six
This is line nine
PS: this outputs the lines in their original order (set "lines=1,4-6,8" and set "lines=8 1 4-6" give the same output (due to how findstr /g works))
I am not really understanding the arrays. I will have another look next week. So far I've got this based on #Stephan answer.
choice /c rs /m "RANGE MODE OR SPECIFIED MODE"
goto:%errorlevel%
:2
:specified
echo:
set /p lines=ENTER SPECIFIC LINES (seperated by spaces)?
(for %%a in (%lines%) do echo %%a:)>lines.txt
for /f "tokens=1,* delims=:" %%a in (
'type file.txt^|findstr /n "^"^|findstr /bg:lines.txt'
) do (
echo/%%b)
del lines.txt
pause
goto :eof
:1
:range
echo:
set /p ran=ENTER RANGE (e.g. 15-25)?
echo %ran%>range.txt
for /f "tokens=1,* delims=-" %%a in (range.txt) do (
set line1=%%a
set line2=%%b)
del range.txt
(for /l %%a in (%line1%,1,%line2%) do echo %%a:)>lines.txt
for /f "tokens=1,* delims=:" %%a in (
'type file.txt^|findstr /n "^"^|findstr /bg:lines.txt'
) do (
echo/%%b)
del lines.txt
pause
goto :eof
Trying to follow arrays through this link I can see when setting elements within the batch but not pointing file.txt. I tried
for /f %%a in ('type file.txt^|echo !elem[%2%]!') do echo %%a
and
for /f "tokens=* delims=" %%a in ('type file.txt^|find /v /n ""') do (
echo/%%a|findstr /l /b "!elem[%2%]!" >nul && echo echo/%%a)
Anyway that is a different question, I have work through that link next week.
Cuts the number of lines from the top or bottom of file.
This is similar to Unix's Tail command of which there is no Windows' equivalent.
To use
Cut
cut {t|b} {i|x} NumOfLines
Cuts the number of lines from the top or bottom of file.
t - top of the file
b - bottom of the file
i - include n lines
x - exclude n lines
Example
cscript //nologo c:\folder\cut t i 5 < "%systemroot%\win.ini"
Copy following lines into cut.vbs
Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout
Set rs = CreateObject("ADODB.Recordset")
With rs
.Fields.Append "LineNumber", 4
.Fields.Append "Txt", 201, 5000
.Open
LineCount = 0
Do Until Inp.AtEndOfStream
LineCount = LineCount + 1
.AddNew
.Fields("LineNumber").value = LineCount
.Fields("Txt").value = Inp.readline
.UpDate
Loop
.Sort = "LineNumber ASC"
If LCase(Arg(1)) = "t" then
If LCase(Arg(2)) = "i" then
.filter = "LineNumber < " & LCase(Arg(3)) + 1
ElseIf LCase(Arg(2)) = "x" then
.filter = "LineNumber > " & LCase(Arg(3))
End If
ElseIf LCase(Arg(1)) = "b" then
If LCase(Arg(2)) = "i" then
.filter = "LineNumber > " & LineCount - LCase(Arg(3))
ElseIf LCase(Arg(2)) = "x" then
.filter = "LineNumber < " & LineCount - LCase(Arg(3)) + 1
End If
End If
Do While not .EOF
Outp.writeline .Fields("Txt").Value
.MoveNext
Loop
End With
For a line count program
Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout
Do Until Inp.AtEndOfStream
Line=Inp.readline
Count = Count +1
Loop
outp.writeline Count

Rename all files in directory based on text they contain

I'm trying to loop through all .lss files in a folder, and grab a string that exists between two tags, save that value and rename the file using that string.
Example:
42982934829.lss -> contains string:
<surveyls_title><![CDATA[J.3200-1118 - Project Title]]></surveyls_title>
Rename to `J.3200-1118 - Project Title.lss`
Here is what I have so far, but I fear my syntax is badly incorrect..
#Echo off
Set Folder=X:\RenameTest
Set Files=*.lss
PushD %Folder%
For %%A in (%Files%) Do For /f %%B IN (
'findstr "<surveyls_title>.*</surveyls_title>" "%ProjectTitle%"'
) Do Call :Rename ..
PopD
Goto :Eof
:Rename
Echo Ren %1 "%ProjectTitle%"
I suppose this is what you want.
#echo off
pushd "X:\RenameTest"
for %%a in (*.lss) do for /f "tokens=3*delims=[]" %%i in ('type "%%a" ^| find "</surveyls_title>"') do echo ren "%%~a" "%%~i%%~xa"
popd
Just remove echo from the line once you are happy with the printed results.
You can also extract the title using Regex : Demo Here
#echo off & color 0A
Title Extract Title using Regex
Set "InputFile=42982934829.lss"
Call :Extract_Title "%InputFile%" Title
Echo %Title%
Pause & Exit
::----------------------------------------------------------------------------------------
:Extract_Title <InputFile> <Title to be Set>
(
echo WScript.StdOut.WriteLine Extract_Title(Data^)
echo Function Extract_Title(Data^)
echo Data = WScript.StdIn.ReadAll
echo Set re = New RegExp
echo re.Global = True
echo re.IgnoreCase = True
echo re.Pattern = "\[CDATA\[(.*?)\]\]"
echo For Each Match in re.Execute(Data^)
echo Title = Match.SubMatches(0^)
echo Next
echo Extract_Title = Title
echo End Function
)>"%tmp%\%~n0.vbs"
for /f "delims=" %%A in ('cscript /nologo "%tmp%\%~n0.vbs" ^< "%~1"') do set "%2=%%A"
If Exist "%tmp%\%~n0.vbs" Del "%tmp%\%~n0.vbs"
Exit /B
::----------------------------------------------------------------------------------------

How to get only the first sequence of numbers in a listing using batch or powershell

What I need is the first sequence of a number in a listing:
The command:
for /f "delims=" %%a in (notas.txt) do #echo %%a
Returns:
Compra cfme NF 12345 de 123 CIA ABC
Pgto dupl. 12345 - 123 CIA ABC
Compra cfme NFS 654321-CIA CBC
Pgto NF 654321 de CIA CBC
But what I need is:
12345
12345
654321
654321
Thanks in advance
There are numerous PowerShell solution/techniques that can perform what is required.
The switch statement can be used with the -File and -Regex parameters.
switch -Regex -File notas.txt {
'\d+' { $Matches[0] }
}
You can also use the Match method from the regex class:
Get-Content notas.txt | Foreach-Object {
[regex]::Match($_,'\d+').Value
}
Both solutions rely on regex matching with \d+ matching one or more consecutive digits. Since we are doing a single match per line, the first match is the only match returned. The regex class method Matches returns multiple matches per string input.
With a Batch file using regex in vbscript you can do something like this :
Demo Here
#echo off & color 0A
Title Extract Numbers from String using Regex with vbscript
Set "InputFile=%~dp0notas.txt"
Set "OutPutFile=%~n0_OutPutFile.txt"
Call :Extract_Number "%InputFile%" CON
Call :Extract_Number "%InputFile%" "%OutPutFile%"
TimeOut /T 3 /NoBreak>nul
If Exist "%OutPutFile%" Start "" "%OutPutFile%" & Exit
::-----------------------------------------------------------------------------------
:Extract_Number <Input> <OutPut>
(
echo WScript.StdOut.WriteLine Extract_Number(Data^)
echo Function Extract_Number(Data^)
echo Data = "%~1"
echo Data = WScript.StdIn.ReadAll
echo Set re = New RegExp
echo re.Global = True
echo re.IgnoreCase = True
echo re.Pattern = "\d{5,}"
echo For Each Match in re.Execute(Data^)
echo Number = Number ^& Match.Value ^& vbCrLF
echo Next
echo Extract_Number = Number
echo End Function
)>"%tmp%\%~n0.vbs"
cscript //nologo "%tmp%\%~n0.vbs" < "%~1" > "%~2"
If Exist "%tmp%\%~n0.vbs" Del "%tmp%\%~n0.vbs"
Exit /B
::----------------------------------------------------------------------------------
This first code does what your question asks, but not what your expected results show:
#echo off
:: Pass the entire line to a subroutine
for /f "delims=" %%a in (notas.txt) do call :process %%a
goto :eof
:process
:: Check if we've evaluated the entire line
if "%1"=="" (
echo No number was found in this line
goto :eof
)
:: Check if the current parameter is only numbers
:: If it is, then echo and move on to the next line
:: If not, use shift to evaluate the next parameter
echo %1|findstr /i /r "[^0-9]" >nul && shift && goto :process
echo %1
goto :eof
2 things. First, I don't know what you want to do if a number isn't found in the line. In the code above I just echo "No number was found in this line".
Second, I presumed "number" to be fully delimited with standard spaces as delimiters. Thus, the code above does NOT return 654321 from the line Compra cfme NFS 654321-CIA CBC because 654321-CIA is not a number delimited by spaces. If you want additional delimiters, then change this line above:
for /f "delims=" %%a in (notas.txt) do call :process %%a
to:
for /f "tokens=1-10 delims=-., " %%a in (notas.txt) do call :process %%a %%b %%c %%d %%e %%f %%g %%h %%i %%j
adding whatever delimiters you want (don't forget a space before the double quote). This line is good for up to 10 entries on a given line. Going up to 26 using tokens=1-26 and %%a through %%z is pretty easy.
Finally -- if you want to pull a non-delimited number -- then that would be a completely different approach. An example would be getting 1356 from PC1356 NLA LOA; or getting 35232 from PC LI-D 35232NDA TTH.

batch script to parse txt file with delimiter as semicolon

my text file is as shown below:
H;SEQUENCENUMMER;TIMESTAMP;VERSION;VALIDITY_FLAG;SID
D;1077;1383519656;"20.0.8-2";1;;
D;1079;1383519657;"20.0.8-2";2;;
i want to parse this using windows batch program and output file will look like as beloW:
H SEQUENCENUMMER TIMESTAMP VERSION VALIDITY_FLAG SID
D 1077 1383519656 "20.0.8-2" 1
D 1078 1383519657 "20.0.8-3" 2
something like a tab delimited
pls suggest
#echo off
setlocal enableextensions enabledelayedexpansion
rem Get a tab character
for /f tokens^=^*^ delims^= %%t in ('forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x09"') do set "tab=%%t"
rem For each line in text file, replace ; with a tab
(for /f "tokens=*" %%l in (plaintext.txt) do (
set "line=%%l"
echo !line:;=%tab%!
)) > output.txt
endlocal
#echo off
setlocal enabledelayedexpansion
if exist output.txt del output.txt
for /f "delims=" %%a in ('type "Your Text File.txt"') do (set $line=%%a
echo !$line:;= !>>output.txt)
You can use nested for-loops as follows:
#echo off
echo.|set a=>outfile.txt
for /f %%A in (infile.txt) do (
for %%B in (%%A) do (
echo.|set /P ="%%B ">>outfile.txt
)
echo.>>outfile.txt
)
You don't really seem to be parsing anything, you are just replacing semicolons with tabs. You can use VBScript to do this. Save the following as "process.vbs"
Option Explicit
Dim Line,Regex
Set RegEx = new RegExp
Regex.Pattern = ";"
Regex.Global=True
Do While Not WScript.StdIn.AtEndOfStream
Line = WScript.StdIn.ReadLine()
Line = Regex.Replace(Line,VBTab)
WScript.Echo Line
Loop
Then you can run it like this:
vbscript /nologo process.vbs < yourfile > newfile

Resources