I have this code:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET /A counter=0
SET /A counter2=0
for /f %%h in (users.txt) do (
set /a counter2=0
set /a counter=!counter!+1
for /f %%i in (users.txt) do (
set /a counter2=!counter2!+1
IF !counter! gtr !counter2!
echo !counter! and !counter2!
)
)
For some reason I the If statement in there errors. If I cross it out it all runs just fine.
What's wrong with my syntax?
Thanks!
EitanT likely has the solution you are looking for, but it doesn't fully explain your problem.
If you remove the IF statement you get this, after the indentation is adjusted to better show the actual logic. The 2nd loop runs inside the 1st.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET /A counter=0
SET /A counter2=0
for /f %%h in (users.txt) do (
set /a counter2=0
set /a counter=!counter!+1
for /f %%i in (users.txt) do (
set /a counter2=!counter2!+1
echo !counter! and !counter2!
)
)
When you put in the IF statement you get this improper code
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET /A counter=0
SET /A counter2=0
for /f %%h in (users.txt) do (
set /a counter2=0
set /a counter=!counter!+1
for /f %%i in (users.txt) do (
set /a counter2=!counter2!+1
IF !counter! gtr !counter2!
echo !counter! and !counter2!
)
)
The IF statement is incomplete - you didn't tell it what to do if true.
If you want the ECHO to be part of the IF then you need to do 1 of 3 things:
1) Append the ECHO to the IF statement
IF !counter! gtr !counter2! echo !counter! and !counter2!
2) Use line continuation to turn the IF and ECHO lines into one logical line
IF !counter! gtr !counter2!^
echo !counter! and !counter2!
3) Add another set of parentheses. Note the opening parenthesis must be on the same line as the IF, and there must be a space in front of it.
IF !counter! gtr !counter2! (
echo !counter! and !counter2!
)
The help system describes the proper syntax for IF. Type HELP IF or IF /? from a command line to get help.
Notice the logic of the code I have posted is different than the EitanT solution. I'm not sure which is correct. Like most programming languages, the indentation does not affect the logic, it is there to make it more obvious to humans what the logic is. Your original indentation indicates the logic that EitanT provided. I ignored the indentation and provided the logic that the computer sees.
BTW - you do not need to expand variables in SET /A statements. The following works fine:
set /a counter=counter+1
Even better, you can use the incrementing assignment operator:
set /a counter+=1
SET /A also supports multiple assignments in one statement:
set /a counter2=0, counter+=1
You do not need to initialize counter2 at the top since you also do it within your 1st loop.
Here is the final code using the logic that I see based on your existing parentheses, ignoring your indentation:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET /A counter=0
for /f %%h in (users.txt) do (
set /a counter2=0, counter+=1
for /f %%i in (users.txt) do (
set /a counter2+=1
IF !counter! gtr !counter2! echo !counter! and !counter2!
)
)
I can spot two problems:
1) The first for loop doesn't have a closing parenthesis:
for /f %%h in (users.txt) do (
set /a counter2=0
set /a counter=!counter!+1
) <---------------------------------- You're missing this ")"!
2) In the second loop, the if statement lacks an opening parenthesis:
IF !counter! gtr !counter2! ( <------ You're missing this "("!
echo !counter! and !counter2!
)
Hope this helps!
Your if statement should either be all on one line, or enclosed in ().
Here is a correction:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET /A counter=0
SET /A counter2=0
for /f %%h in (users.txt) do (
set /a counter2=0
set /a counter=!counter!+1
for /f %%i in (users.txt) do (
set /a counter2=!counter2!+1
IF !counter! gtr !counter2! (
echo !counter! and !counter2!
)
)
)
Correct indentation can help you track down bracketing errors.
Related
I have a huge file. I need to find the line containing the pattern abc_x and replace its value 0.34 to 10% increased value. And then copy the entire file (with replaced values) into a new file. I am new to Tcl, please let me know how to do this.
Thanks in advance.
There are three key stages to this:
Reading the old file in.
Making the update to the data in memory.
Writing the new file out.
The first and third stages are pretty standard:
set f [open input.txt]
set data [read $f]
close $f
set f [open output.txt "w"]
puts -nonewline $f $data
close $f
So now it's just about doing the transformation in memory. The best answer to this depends on the version of Tcl you're using. In all current production versions, it's probably best to split the data into lines and iterate over them, checking whether a line matches and, if it does, performing the transformation.
set lines {}
foreach line [split $data "\n"] {
if {[matchesPattern $line]} {
set line [updateLine $line]
}
lappend lines $line
}
set data [join $lines "\n"]
OK, in that code above, matchesPattern and updateLine are stand-ins for the real code, which might look like this:
if {[regexp {^(\s*abc_x\s+)([\d.]+)(.*)$} $line -> prefix value suffix]} {
# Since we matched the prefix and suffix, we must put them back
set line $prefix[expr {$value * 1.1}]$suffix
}
Composing all those pieces together gets this:
set f [open input.txt]
set data [read $f]
close $f
set lines {}
foreach line [split $data "\n"] {
if {[regexp {^(\s*abc_x\s+)([\d.]+)(.*)$} $line -> prefix value suffix]} {
set line $prefix[expr {$value * 1.1}]$suffix
}
lappend lines $line
}
set data [join $lines "\n"]
set f [open output.txt "w"]
puts -nonewline $f $data
close $f
In 8.7 you'll be able to write the update more succinctly:
set data [regsub -all -line -command {^(\s*abc_x\s+)([\d.]+)} $data {apply {{-> prefix value} {
# Since we matched the prefix, we must put it back
string cat $prefix [expr {$value * 1.1}]
}}}]
(Getting shorter than this would really require a RE engine that supports lookbehinds; Tcl's standard one does not.)
I have three text file.
C:\content1.txt
C:\content2.txt
C:\content3.txt
text file contains random links
https://example2.com/file/casdqwe/test1.rar
https://example2.com/file/casdqwe/test2.rar
https://example5.com/file/casdqwe/test3.rar
i want to remove the the domain names and save the last part only. output
test1.rar
test2.rar
test3.rar
and save it in original file no need any confirmation.
notepad++ regex replace work but i am not sure how to do it in
using Powershell/VBS script any will work fine.
Find What: https://example\.com[^\s\[\]<'\"]+/([^\s\[\]<'\"]+)
Replace with: $1
and powershell i have something like that
(Get-Content -path C:\content1.txt -Raw) -replace "https://example2.com/file/asdcb6af26/test.rar" -replace "https://example2.com/file/(.*)\/(.*)", '$2'
Use these simple powershell commands:
(Get-Content C:\content1.txt) -creplace '(?s)^.*/', '' | Set-Content C:\content1.txt
(Get-Content C:\content2.txt) -creplace '(?s)^.*/', '' | Set-Content C:\content2.txt
(Get-Content C:\content3.txt) -creplace '(?s)^.*/', '' | Set-Content C:\content3.txt
Let me know if you have any questions.
Refer to your previous question here, you can give a try for this batch file that use Regex in vbscript.
#echo off
Mode 85,35 & color 0A
Title Replace Multi String using Regex with vbscript into Folder with text files
Set "Source_Folder=C:\test"
Set "Backup_Folder=%userprofile%\Backup_Contents\"
Rem :: Just make a backup of your folder and its contents if something went wrong!
If Not Exist "%Backup_Folder%" XCopy "%Source_Folder%" "%Backup_Folder%" /D /Y /E /F >%~dp0BackupLogFile.txt
Set "VBSFILE=%tmp%\%~n0.vbs" & Call :CreateVBS
Set "TmpFile=%Temp%\%~n0.tmp"
for /R "%Source_Folder%" %%f in (*.txt) do (
echo( ------------------------------------------
echo Replacing Contents of "%%f"
echo( ------------------------------------------
Call :Search_Replace "%%f" "%TmpFile%"
Move /Y "%TmpFile%" "%%f">nul
)
If Exist "%VBSFILE%" Del "%VBSFILE%"
Timeout /T 3 /NoBreak>nul & Exit
::-----------------------------------------------------------------------------
:CreateVBS
(
echo WScript.StdOut.WriteLine Search_Replace(Data^)
echo Function Search_Replace(Data^)
echo Dim strPattern, strReplace, strResult,oRegExp
echo Data = "%~1"
echo Data = WScript.StdIn.ReadAll
echo strPattern1 = "(\x22<|<)([\s\S]*?)(/>\x22|>| />\x22| />| \x22>)"
echo strReplace1 = "[abc]$2[/abc]"
echo strPattern2 = "(http:\/\/|https:\/\/)(.+)[^\s\[\]<]\/([^\s\[\]<].+)"
echo strReplace2 = "$3"
echo Set oRegExp = New RegExp
echo oRegExp.Global = True
echo oRegExp.IgnoreCase = True
echo oRegExp.Pattern = strPattern1
echo strResult1 = oRegExp.Replace(Data,strReplace1^)
echo oRegExp.Pattern = strPattern2
echo strResult2 = oRegExp.Replace(strResult1,strReplace2^)
echo Search_Replace = strResult2
echo End Function
)>"%VBSFILE%"
Exit /b
::----------------------------------------------------------------------------
:Search_Replace <InputFile> <OutPutFile>
Cscript /nologo "%VBSFILE%" < "%~1" > "%~2"
Exit /B
::----------------------------------------------------------------------------
I'm guessing that maybe,
\bhttps?:\/\/.*\/
simply replaced with an empty string might work just fine.
If you wish to simplify/modify/explore the expression, it's been explained on the top right panel of regex101.com. If you'd like, you can also watch in this link, how it would match against some sample inputs.
I need help with tcl. I have a text file with the following format:
Main = 1
Bgp = 0
Backup = 1
I need to increment the integer value by 1 for each item, for example replacing Main = 1 with Main = 2, and so on.
Another approach:
# read the data
set f [open file]
set data [read -nonewline $f]
close $f
# increment the numbers
regsub -all {=\s*(\d+)\s*$} $data {= [expr {\1 + 1}]} new
set new [subst -novariables -nobacklashes $new]
# write the data
set f [open file w]
puts $f $new
close $f
That regsub command will replace Main = 1 with Main = [expr {1 + 1}], and then the subst command actually invokes the expr command to compute the new value
(Changed my answer: I was a little irritable, sorry.)
If the text to be processed is in a variable called data, one can turn the text into a list of words and go through them three at a time like this:
set result ""
foreach {keyword op value} [split [string trim $data]] {
append result "$keyword $op [incr value]\n"
}
In this case, each keyword (Main, Bgp, Backup, ...) ends up inside the loop variable keyword, each equals sign (or whatever is in the second position) ends up inside the loop variable op, and each value to be incremented ends up inside value.
(When splitting, it's typically a good idea to trim off white-space at the beginning and end of the text first: otherwise one can get empty "ghost" elements. Hence: split [string trim $data])
We can read the data from the file "datafile" like this:
set f [open datafile r+]
set data [read $f]
Note that we use r+ to be able to both read from and write to the file.
Once we have processed the data, we can write it back at the beginning of the file like this:
seek $f 0
puts -nonewline $f $result
close $f
or possibly like this, which means we didn't have to open the file with r+:
close $f
set f [open datafile w]
puts -nonewline $f $result
close $f
Putting it together:
set f [open datafile r+]
set data [read $f]
set result ""
foreach {keyword op value} [split [string trim $data]] {
append result "$keyword $op [incr value]\n"
}
seek $f 0
puts -nonewline $f $result
close $f
This procedure can also be simplified a bit using the standard package fileutil, which can take care of the file opening, closing, reading, and writing for us.
First, we put the processing in a procedure:
proc process data {
foreach {keyword = value} [split [string trim $data]] {
append result "$keyword ${=} [incr value]\n"
}
return $result
}
Then we can just ask ask updateInPlace to update the contents of the file with new contents processed by process.
package require fileutil
::fileutil::updateInPlace datafile process
And that's it.
Documentation:
append,
close,
fileutil (package),
foreach,
incr,
open,
package,
proc,
puts,
read,
return,
seek,
set,
split,
string
How can I return the matched value from a regular expression Perl execution?
I want to further use the match in my batch file.
Batch file:
perl -p -e "ab{2}" c:\file.txt
REM echo %var% how can I get the result from perl?
REM do something with %var%
File file.txt:
abbreviation
Update for zb226:
test
Filename: dynamicFile.txt
Property: some property to neglect
Message: the message I want
Time: dynamicTime
You need the FOR command for that:
#ECHO OFF
FOR /F "delims=" %%I IN ('perl -ne "print $1.\"\n\" if ~/(ab{2})/" c:\file.txt') DO SET match=%%I
ECHO match: %match%
Note that this will return the last match - which does not matter with your example regexp ab{2}, as that will always return abb or nothing.
Edit 1: Forgot to add a newline in the perl onliner - alternatively you can use Andrey's perl -pe ... version, which does not require printing the newline.
Edit 2: Then again, Andrey's one-liner matches the regexp only at the beginning of a line, which is not what your question suggests. Also it prints non-matching lines, as you already noticed. I can't think of an easy fix for the perl -pe version...
Edit 3: Here's a quick and dirty solution for the additional information you've provided in the comment.
#ECHO OFF
FOR /F "usebackq delims=" %%I IN (`perl -e "local $/ = undef; open my $h, '<', $ARGV[0]; my $x = <$h>; print $1 if $x=~/Filename: dynamicFile.txt.*?Message: (.*?)Time/s;" c:\file.txt`) DO SET match=%%I
ECHO match: %match%
With a test file of...
test
Filename: dynamicFile.txt
Property: some property to neglect
Message: the message I want
Time: dynamicTime
----
Filename: someOtherFile.txt
Property: some property to neglect
Message: someMessage
Time: dynamicTime
...this outputs:
match: the message I want
perl -p -e "s/^(ab{2}).*$/\1/" c:\file.txt
perl -lne "print $1 if /(ab{2})/" C:\file.txt
I am looking for a simple batch solution for the following:
In a number of files I want to replace a string with another one. Can do this with Notepad++. However, each new string has to be unique, read from a list of new strings.
So, if 'abc' occurs in some files, and I have a list with new strings, replace it this way:
abc --> alex
abc --> ben
abc --> chris
abc --> dave
etc.
I can have a txt file with the new strings to read from.
Hope someone has a solution for me!
Many thanks,
Lennart
Would a Perl script work?
my #words = qw(alex ben chris dave ...);
while (<>) {
s/abc/shift #words/ge;
print;
}
If you want the word list to loop:
my #words = qw(...);
my $i = 0;
while (<>) {
# I know I should have written this in a more readable way...
s{abc}{$words[$i++] // $words[$i=0]}ge;
print;
}
Or as batch script
#echo off
setlocal Disabledelayedexpansion
set "wordlist=alex ben chris dave"
for /F "tokens=* delims=" %%a in (myFile.txt) do (
set "line=%%a"
setlocal Enabledelayedexpansion
for /F "tokens=1,*" %%b in ("!wordlist!") do (
set "newline=!line:abc=%%b!"
(echo(!newline!)
if !newline! NEQ !line! (
endlocal
set "wordlist=%%c"
) ELSE (
endlocal
)
)
)
Edit Change to a "!" safe variant
Try and find a sed executable for Windows which supports the -i (--inline) switch and your job will become a toddler's task!