Using FINDSTR to locate a string using regex - findstr

Hello I am trying to match lines in a text file using this:
findstr /i "6.0.0.0.[0-9][0-9][0-9][0-9] Wave Embedded 6.0 ([0-9][0-9][0-9][0-9])" C:\IOManifest.txt
but all it does is open up the file at C:\IOManifest.txt and print it to screen...
a correct match would be "6.0.0.0.3456 Wave Embedded 6.0 (3957)
what am i doing wrong?

This works:
echo 6.0.0.0.3456 Wave Embedded 6.0 (3957) | findstr /i "6.0.0.0.[0-9][0-9][0-9][0-9] Wave Embedded 6.0 ([0-9][0-9][0-9][0-9])"
So you should use:
type C:\IOManifest.txt | findstr /i "6.0.0.0.[0-9][0-9][0-9][0-9] Wave Embedded 6.0 ([0-9][0-9][0-9][0-9])"

Related

How to locate Executable paths with WMIC and Powershell

I am using both python and Powershell and I can't figure out the discrepancies between the 2. Obviously one is using WMIC and the other is using Get-ItemProperty -path.
How can I get the path's from the WMIC for all executables. Python example as Follow:
if use_cached_program_list is False:
# traverse the software list
Data = subprocess.check_output(['wmic', 'product', 'get', 'name'])
program_list = sorted(str(Data).split("\\r\\r\\n"))
# Filter out string that contain no alphanumeric characters
program_list = [x.strip() for x in program_list if re.search('[a-zA-Z0-9]', x) is not None]
# Get absolute path of current file
sp = pathlib.Path(__file__).parent.absolute()
cached_file_path = os.path.join(sp, "Caches", cache_file)
with open(cached_file_path, "w") as fs:
# arrange the string and output to file
for i in range(0, len(program_list)):
item = program_list[i]
fs.write(item + "\n")
Returns an output of 477 "Programs" I use quotes on programs cause it returns, all sdk's whether it is extensions or runtimes as displayed below:
Active Directory Authentication Library for SQL Server
Adobe Acrobat Reader DC
Adobe Refresh Manager
Advanced IP Scanner 2.5
Application Verifier x64 External Package
Application Verifier x64 External Package
Application Verifier x64 External Package
Application Verifier x64 External Package
When I use Powershell, and the Get-ItemProperty and search the registry here is the code:
Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*" | Where-Object {$q + $_."(default)" -ne $null} | Select-Object #{ expression={$_.PSChildName}; label='Program'} ,#{ expression={$q + $_."(default)" +$q}; label='CommandLine'} | Export-Csv -Path .\programs.csv -Encoding ascii -NoTypeInformation
I have not updated this code above to remove all Double Quotations, but none the less still has same results.
To remove all Double Quotation marks the code is:
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*" | Where "(default)" -ne $null |
Select #{ E={$_.PSChildName}; N='Program'} ,#{ E={$_."(default)".Trim('"')}; N='CommandLine'} |
export-csv .\programs.csv -Encoding ascii -NoType
here is the output:
"7zFM.exe","C:\Program Files\7-Zip\7zFM.exe"
"AcroRd32.exe","C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"
"Adobe Audition CC.exe","""C:\Program Files\Adobe\Adobe Audition CC 2019\Adobe Audition CC.exe"""
"Adobe Media Encoder.exe","""C:\Program Files\Adobe\Adobe Media Encoder CC 2019\Adobe Media Encoder.exe"""
"Adobe Premiere Pro.exe","""C:\Program Files\Adobe\Adobe Premiere Pro CC 2019\Adobe Premiere Pro.exe"""
"AfterFX.exe","C:\Program Files\Adobe\Adobe After Effects CC 2019\Support Files\AfterFX.exe"
This results in only 75 applications installed. Reason is that it checks the uninstall key, and from what I know it appears many companies who develop software simply do not adhere to Microsoft's policies on registry keys. or did not use an MSI installer.
Now before anyone starts saying the Registry keys needed to search are both
HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*
HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*
Whether I use one or both of those registry paths they return the exact same results with both 32bit and 64 bit.
The Goal:
I am trying to get WMIC to return the path for all of the executables, and I will filter out the unwanted stuff later.
Any ideas?
Thank you
This is the same thing as "wmic product get name" in powershell. This class tends to be slow since it verifies every msi.
get-ciminstance win32_product | % name
Or you can do (powershell 5.1):
get-package | % name

What is the windows equivalent of Linux command wc -l?

I have a piece of code that is meant to send the following to the linux command line:
wc -l C:/inputdirectory/P*
However, I need to run this script in Windows, and am trying to find the equivalent command. I have tried
find /c /v C:/inputdirectory/P*
But this throws an error, that /v is not a valid command. Can you please tell me why this isn't working?
*note, the command itself doesn't say "inputdirectory", it has the correct directory, it's just too tedious and private to type out
Courtesy of Eryk Sun:
Try searching for "", i.e. an empty string; use only backslash as the path separator; and quote the path if it has spaces in it:
find /c /v "" "C:\inputdirectory\P*"
From cmd.exe (the Command Prompt / a batch file), which is obsolescent:
Use the accepted answer.
From PowerShell, you have two options:
Option A (suboptimal): Use the accepted answer too, with a small tweak:
find --% /c /v "" "C:\inputdirectory\P*"
Note: --%, the stop-parsing symbol, tells PowerShell to pass subsequent arguments through as-is to the target program (after expanding cmd-style environment-variable references such as %USERNAME%, if any).
In the case at hand, this prevents PowerShell from parsing "" and - mistakenly - neglecting to pass it through to the external target program (find.exe).
For a summary of PowerShell's highly problematic handling of quotes when calling external programs, see this answer.
Output from the above find.exe command - and, indeed, any external program, is just text, and in this case it looks something like this:
---------- PFILE1.TXT: 42
---------- PFILE2.TXT: 666
...
While this output is easy to grasp for a human observer, it makes subsequent programmatic processing cumbersome, because text parsing is required.
Using a PowerShell-native command (cmdlet), as described below, offers more flexibility, because PowerShell commands typically emit objects with typed properties, which greatly facilitates subsequent processing.
Option B (preferred): Use PowerShell's own Measure-Object cmdlet with the -Line switch:
Note: While this command is more verbose than the find solution, it ultimately offers more flexibility due to outputting objects with typed properties, which greatly facilitates subsequent processing; additionally, PowerShell's sophisticated output-formatting system offers user-friendly default representations.
Get-Item -Path "C:\inputdirectory\P*" -PipelineVariable file | ForEach-Object {
Get-Content -LiteralPath $file |
Measure-Object -Line |
Select-Object #{ Name='File'; Expression={ $file } }, Lines
}
The above outputs objects that have a .File and .Lines property each, which PowerShell prints as follows by default:
File Lines
---- -----
C:\inputdirectory\Pfile1.txt 42
C:\inputdirectory\Pfile2.txt 666
...
In addition to a nicer presentation of the output, the object-oriented nature of the output makes it easy to programmatically process the results.
For instance, if you wanted to limit the output to those files whose line count is 100 or greater, pipe to the following Where-Object call to the above command:
... | Where-Object Lines -ge 100
If you (additionally) wanted to sort by highest line count first, pipe to the Sort-Object cmdlet:
... | Sort-Object -Descending Lines
How can I count the lines in a set of files?
Use the following batch file (CountLines.cmd):
#echo off
Setlocal EnableDelayedExpansion
for /f "usebackq" %%a in (`dir /b %1`) do (
for /f "usebackq" %%b in (`type %%a ^| find "" /v /c`) do (
set /a lines += %%b
)
)
echo %lines%
endlocal
Usage:
CountLines C:/inputdirectory/P*
Further Reading
An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
dir - Display a list of files and subfolders.
find - Search for a text string in a file & display all the lines where it is found.
for /f - Loop command against the results of another command.

Find a string and replace specific letters in batch file

I have a to create an autosys job to trigger a batch file which would find a specific string and then replace the next 4 characters.
For example if file (with multiple lines) has below content and i am searching for played
the mad fox jumped of the old vine and
played soccer.
I should replace "socc" with "INFA"
I am new to batch files and my lead has been insisting that i do this using a batch file only. Any help would be greatly apprciated.
Thanks,
Joy
#echo off &setlocal
set "search=search string"
set "replace=kordo anstataui"
set "textfile=file.txt"
set "newfile=new.txt"
(for /f "delims=" %%i in ('findstr /n "^" "%textfile%"') do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
))>"%newfile%"
type "%newfile%"
Apparently you are searching for "played " with a space at the end, although your question is a bit vague.
See my hybrid JScript/batch utility called REPL.BAT that does regular expression search and replace. It works on any modern version of Windows from XP onward, and it does not require installation of any 3rd party executeables.
Using REPL.BAT:
type "yourFile.txt"|repl "played ...." "played INFA" >"yourFile.txt.new"
move /y "yourFile.txt.new" "yourFile.txt" >nul
I use this at times: sar.bat
::Search and replace
#echo off
if "%~3"=="" (
echo.Search and replace
echo Syntax:
echo "%~nx0" "filein.txt" "fileout.txt" "regex" "replace_text" [first]
echo.
echo.EG: change the first time apple appears on each line, to orange
echo."%~nx0" "my text old.txt" "my text changed.txt" "apple" "orange" first
echo.
echo.People that are familiar with regular expressions can use some:
echo.
echo.Change every line starting from old (and everything after it^) to new
echo."%~nx0" "my text old.txt" "my text changed.txt" "old.*" "new"
echo.
echo.If [first] is present only the first occurrence per line is changed
echo.
echo.To make the search case sensitive change
echo.IgnoreCase= from True to False
echo.
pause
goto :EOF
)
if "%~5"=="" (set global=true) else (set global=false)
set s=regex.replace(wscript.stdin.readall,"%~4")
>_.vbs echo set regex=new regexp
>>_.vbs echo regex.global=%global%
>>_.vbs echo regEx.IgnoreCase=True
>>_.vbs echo regex.pattern="%~3"
>>_.vbs echo wscript.stdOut.write %s%
cscript /nologo _.vbs <"%~1" >"%~2"
del _.vbs
Get yourself a copy of sed for your OS and call it from a batch file.
sed -e 's/socc/INFA/g' inputFileName > outputFileName
#echo off
setlocal EnableDelayedExpansion
set "search=played "
set replacement=INFA
set numChars=4
set line=the mad fox jumped of the old vine and played soccer.
rem The characters after the equal-signs are Ascii-254
for /F "tokens=1* delims=■" %%a in ("!line:%search%=■!") do (
set "rightPart=%%b"
set "line=%%a%search%%replacement%!rightPart:~%numChars%!"
)
echo !line!
Output:
the mad fox jumped of the old vine and played INFAer.
You must insert previous code into a loop that process the entire file. I left that part as an exercise for you...

batch script - to remove duplicate tokens in file

I have duplicate tokens in text file I would like to create new text file without the duplicate tokens (keeping the delimiters)
The delimiter is:~#^*^#~
example file:
aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~xxx~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb~#^*^#~aaa~#^*^#~bbb
Result should be:
aaa~#^*^#~bbb~#^*^#~xxx
I found script that remove duplicate lines:
==================================
#echo off > outfile
if %1'==' echo which file? && goto :eof
if not exist %1 echo %1 not found && goto :eof
for /f "tokens=* delims= " %%a in (%1) do (
find "%%a" < outfile > nul
if errorlevel 1 echo %%a >> outfile
)
The script work nice for duplicate lines,
So i modified the delims from:
"tokens=* delims="
to
"tokens=* delims=~#^*^#~"
But it wont work, What am i doing wrong? is one of the delimiter characters reserved word?
Thank you for any suggestion.
The FOR DELIMITERS option treats each character as a delimiter. You cannot use a sequence of characters as a delimiter, so it will not help in your case.
Windows batch is a marginal text processor for simple tasks. You have a particularly nasty problem for a Windows batch file. It might be doable, but the code would be complicated and slow at best.
I strongly advise you use some other tool better suited for text processing. I believe any of the following could be used:
VBscript
JavaScript
Powershell
3rd party tools like Gnu sed for Windows, perl, ... many more
Windows batch is probably about the worst choice you could make, especially for your problem. (this is coming from someone who really enjoys using batch)

How to do this in PowerShell? Or : what language to use for file and string manipulation?

What language should I use for file and string manipulation?
This might seem objective, but really isn't I think. There's lot to say about this. For example I can see clearly that for most usages Perl would be a more obvious candidate than Java. I need to do this quite often and at this time I use C# for it, but I would like a more scriptlike language to do this.
I can imagine Perl would be a candidate for it, but I would like to do it in PowerShell since PowerShell can access the .NET library (easy). Or is Python a better candidate for it? If I have to learn a new language, Python is certainly one on my list, rather than Perl.
What I want to do for example, is to read a file, make some changes and save it again. E.g.: open it, number all lines (say with 3 digits) and close it.
Any example, in any language, would be welcome, but the shorter the better. It is utility scripting I'm after here, not OO, TDDeveloped, unit-tested stuff of course.
What I would very much like to see is something as (pseudocode here):
open foobar.as f
foreach line in f.lines
line.addBefore(currenIteratorCounter.format('ddd') + '. ')
close f
So:
bar.txt
Frank Zappa
Cowboy Henk
Tom Waits
numberLines bar.txt
bar.txt
001. Frank Zappa
002. Cowboy Henk
003. Tom Waits
UPDATE:
The Perl and Python examples here are great, and definitely in the line of what I was hoping and expecting. But aren't there any PowerShell guys out there?
This is actually pretty easy in PowerShell:
function Number-Lines($name) {
Get-Content $name | ForEach-Object { $i = 1 } { "{0:000}. {1}" -f $i++,$_ }
}
What I'm doing here is getting the contents of the file, this will return a String[], over which I iterate with ForEach-Object and apply a format string using the -f operator. The result just drops out of the pipeline as another String[] which can be redirected to a file if needed.
You can shorten it a little by using aliases:
gc .\someFile.txt | %{$i=1}{ "{0:000}. {1}" -f $i++,$_ }
but I won't recommend that for a function definition.
You way want to consider using two passes, though and constructing the format string on the fly to accommodate for larger numbers of lines. If there are 1500 lines {0:000} it won't be sufficient anymore to get neatly aligned output.
As for which language is best for such tasks, you might look at factors such as
conciseness of code (Perl will be hard to beat there, especially that one-liner in another answer)
readability and maintainability of code
availability of the tools (Perl and Python aren't installed on Windows by default (PowerShell only since Windows 7), so deployment might be hindered.)
In the light of the last point you might even be better off using cmd for this task. The code is similarly pretty simple:
#echo off
setlocal
set line=1
for /f "delims=" %%l in (%1) do call :process %%l
endlocal
goto :eof
:process
call :lz %line%
echo %lz%. %*
set /a line+=1
goto :eof
:lz
if %1 LSS 10 set lz=00%1&goto :eof
if %1 LSS 100 set lz=0%1&goto :eof
set lz=%1&goto :eof
goto :eof
That assumes, of course, that it has to run somewhere else than your own machine. If not, then use whatever fits your needs :-)
perl -i -ne 'printf("00%d. %s",$.,$_)' your-filename-here
You may want %03d instead.
It isn't what you wanted, but please recall findstr.exe(and find.exe) at times...
findstr /n ".*" filename
find "" /v /n filename
Python
target = open( "bar_with_numbers.txt", "w" )
source = open( "bar.txt", "r" )
for count, line in enumerate( source ):
target.write( "%3d. %s\n" % ( count+1, line ) )
source.close()
target.close()
First, it's a bad policy to "update" files in place. In the long run, this becomes a regrettable decision because debugging is made harder by the loss of history.
If you use OS redirection features, this program can be simplified.
import sys
for count, line in enumerate( sys.stdin ):
sys.stdout.write( "%3d. %s\n" % ( count+1, line ) )
Then you can run this enumerate.py as follows
python enumerate.py <bar.txt >bar_with_numbers.txt
More importantly, you can also do this.
python enumerate.py <bar.txt | the_next_step
On a Debian system (and probably other linux distros) you could do this:
$ nl -w 3 -n rz -s ". " [filename] > [newfilename]
Definitely Perl. It supports inline replacement (on Windows you have to start the script with perl .i.bak (because Windows cannot do this inline and creates a .bak file with the same name.)
open(IN,'+>'.$yourfile) || die "Can not open file $yourfile: $!";
my $line_no = 1;
while(<IN>){
print "$line_no. $_";
$line_no++;
}
close IN;
Code just typed from memory without testing. But that should work.
You probably want to add some logic for formatting $line_no (e.g. first count lines and then add as much zero digits as you need.)

Resources