checking lines in a text files agaist another text file - powershell

I have two textfiles, how can i compare them?? Basically what i am after is somthing that take the first line from text file 1 and compares it against all the lines in text file 2, if that line does not appear write that line to text file 3.
Then check the next line in text file 1 agaist all the lines in text file 2 and so on.

The problem is trivial if you have a copy of grep for Windows. One good free source is GnuWin. You can download individual utilities like grep from the packages link, or you can get the entire GnuWin suite using the Download all link (click on the download button at the beginning of that page).
grep -v -x -F -f file2.txt file1.txt >file3.txt
-v = Inverts the match logic - lists lines that don't match
-x = The entire line must match exactly
-F = The search strings are string literals instead of regular expressions
-f file1.txt = get the search strings from file1.txt
You can almost do the same thing using the native FINDSTR command, except there are 2 problems:
1) Any backslash character \ in a search string must be escaped as \\, even when specifying a literal search.
2) There is a nasty FINDSTR bug that causes some matches to be missed if multiple case sensitive literal search strings are used.
See What are the undocumented features and limitations of the Windows FINDSTR command? for a "complete" list of undocumented FINDSTR issues.
The following will work as long as it is acceptable to do a case insensitive search and file2 does not contain any \ characters:
findstr /x /v /i /l /g:file2.txt file1.txt >file3.txt
The backslash limitation can be eliminated by creating a temp file that escapes the backslashes. It is a bit of code, but the end result still runs fairly quickly. The search must still be case insensitive.
#echo off
setlocal disableDelayedExpansion
::Define the files
set "file1=test1.txt"
set "file2=test2.txt"
set "file3=test3.txt"
::Create an LF variable containing a line feed character
set LF=^
::The above 2 blank lines are critical - do not remove
::Create a modified version of file2 that escapes any backslash
::EOL is set to a linefeed so that all non blank lines are preserved
::Delayed expansion is toggled on and off to protect ! characters
>"%file2%.mod" (
for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%A in ("%file2%") do (
set "ln=%%A"
setlocal enableDelayedExpansion
echo(!ln:\=\\!
endlocal
)
)
::Find lines in file1 that are missing from file2.mod
findstr /vixlg:"%file2%.mod" "%file1%" >"%file3%"
::Delete the temporary file2.mod
del "%file2%.mod"
It is relatively simple to write a robust native batch solution using 2 FOR loops, but the performance will deteriorate quickly if the files are large.
#echo off
setlocal disableDelayedExpansion
::Define the files
set "file1=test2.txt"
set "file2=test.txt"
set "file3=test3.txt"
::Create an LF variable containing a line feed character
set LF=^
::The above 2 blank lines are critical - do not remove
::Find lines in file1 that are missing from file2.mod
::EOL is set to a linefeed character so that all non blank lines are preserved
>"%file3%" (
for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%A in ("%file1%") do (
set "found="
for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%B in ("%file2%") do (
if %%A==%%B set found=1
)
if not defined found echo %%A
)
)
There may be a simple and efficient native PowerShell solution, but that is not my expertise.

Related

How do I pass the input from another perl script in batch file

I have a batch file and contains two perl codings and for Example:
MyBatchfile:
rem This perl coding input is Filename output as an number.
perl -w E:\Testing\PerlFile_1.pl %1
Need to save the number and produce the same as an input for the second script.
rem This perl coding input is as number from the previous perl script.
perl -w E:\Testing\PerlFile_2.pl %1
How do I pass the output (Number) from first script into the second script as an input.
You can get the output of a command using:
for /f "delims=" %%p in ('myCommand goes here') do (
set myVar=%%p
)
REM here myVar has the output of the command issued in the above loop
REM assuming that %1 represents the paramter here, I replaced it with the variable above
perl -w E:\Testing\PerlFile_2.pl %myVar%
for /f is used in batch to parse either the contents of the file (in (filename.extension)), a string (in ("myString")) or command outputs (in ('myCommand')). Note the differences in quotation used to determine which one is used.
%%p is the loops parameter and will hold the value of the current iteration. This will be the value in your case. However as this will only exists during the loop we save it to a variable for later use.

Explain batch command please

I want to create a folder with the name of the current date and time.
After searching a lot i found this which actually works.
Can someone explain what these batch commands do?
set timestamp=%DATE:/=-%#%TIME::=-%
set timestamp=%timestamp: =%
mkdir "%timestamp%"
Insert echo statements between the lines and you can see what the value of timestamp is
set timestamp=%DATE:/=-%#%TIME::=-%
echo %timestamp%
set timestamp=%timestamp: =%
echo %timestamp%
mkdir "%timestamp%"
Basically, the code is just removing the forward slash from the date and the colon from time since those are not valid directory names replacing them with hypens.
Read set /? Environment variable substitution to get a better idea.
set timestamp=%DATE:/=-%#%TIME::=-%
That's a string replacement.
1st:
%DATE:/=-% Replaces "/" character to "-" character in the DATE variable
(See: Echo %DATE% on your console)
2nd:
Adds the "#" character to the string after the DATE var and before the TIME var.
3rd:
%TIME::=-% Replaces ":" character to "-" character.
(See: Echo %Time% on your console)
set timestamp=%timestamp: =%
Next in that replacement replaces itself spaces to any characarter (so deletes spaces), but really any space is given so is not necessary in your example code.
You can learn more about Variable string replacement here: http://ss64.com/nt/syntax-replace.html
Also you can simplify your code 'cause no need to setting the value first:
mkdir "%DATE:/=-%#%TIME::=-%"

WindowsCommand Line > Edit a specific string (containing an equals sign) from a text file

I've spent some time poking around stackoverflow and the net in general looking for a well described answer to this problem.
I have a piece of software that installs itself and reads a .ini file. This .ini is of variable size and variable line numbers. The style of every line is something like the following:
setting1=contents
setting2=more,contents
setting3=different type of contents
setting4=youget/theidea
I need to search this text file for a few specific lines, let's say it's the following:
Username=Tommy
Servername=HAL2000
And then replace the values after the equals sign (i.e. change Tommy to Timmy). My problem is that all of the scripting I've found and tried to incorporate either sees the values above as a variable (i.e. username becomes a variable with value "Tommy") or when I go to replace Tommy with timmy, the .ini file ends up replacing EVERY line in the file with Username=Tommy.
I've since deleted both of these scripts and moved on, but the more I think about it the more I want to go back and do this script.
Only rule is that is HAS to be in Windows command line with commands native to XP. No third party programs, no python, no perl, nothing but Windows command line that can be run out of a .bat file.
The a_horse_with_no_name solution works perfectly well for your requirements. It can be made a bit less clumsy and more efficient by eliminating the CALLs. The MOVE command is used to overwrite the original file with the new data.
#echo off
>"test.ini.new" (
for /f "usebackq tokens=1* delims==" %%A in ("test.ini") do (
if %%A==Username (
echo %%A=Timmy
) else if %%A==Servername (
echo %%A=HAL2001
) else echo %%A=%%B
)
)
move /y "test.ini.new" "test.new"
The above assumes every line in the file meets your stated format. But often times an .INI file also has comment lines that do not meet the format that should be preserved. The FOR loop solution can be extended to support that, but it becomes even more complicated, and slower.
You never explicitly stated the order of the lines is important - often times the order of lines in a .INI file is not important. Here is a really simple solution that uses FINDSTR to strip out the existing Username and Servername lines and then appends the new values to the end. All unchanged lines will be preserved, regardless of format. The changed lines always appear at the end.
#echo off
>"test.ini.new" (
findstr /v "^Username= ^Servername=" "test.ini"
echo Username=Timmy
echo Servername=HAL2001
)
move /y "test.ini.new" "test.new"
Batch is really a poor platform for processing text files. It is often slow and overly complicated. It looks like your file is small, and your requirements are relatively simple. But many seemingly simple requests are a beast to do in pure batch.
JScript is much better for processing text, and it is native to XP and beyond. It has full regex support. I have written a hybrid batch/JScript utility script that can be used to perform search and replace operations on the contents of text files. It is very fast, powerful, and simple to use. A solution to your problem is implemented as:
#echo off
type "test.ini" | repl "^Username=.*$" "Username=Timmy" | repl "^Servername=.*$" "Servername=HAL2001" >"test.ini.new"
move /y "test.ini.new" "test.new"
or a bit more concisely as:
#echo off
type "test.ini" | repl "^(Username=).*$" "$1Timmy" | repl "^(Servername=).*$" "$1=HAL2001" >"test.ini.new"
move /y "test.ini.new" "test.new"
Below is the REPL.BAT utility script. Full documentation is embedded within the script. The documentation can also be accessed from the command prompt by typing REPL /?. The script should either be in your current directory, or else somewhere in your PATH.
#if (#X)==(#Y) #end /* Harmless hybrid line that begins a JScript comment
::************ Documentation ***********
:::
:::REPL Search Replace [Options [SourceVar]]
:::REPL /?
:::
::: Performs a global search and replace operation on each line of input from
::: stdin and prints the result to stdout.
:::
::: Each parameter may be optionally enclosed by double quotes. The double
::: quotes are not considered part of the argument. The quotes are required
::: if the parameter contains a batch token delimiter like space, tab, comma,
::: semicolon. The quotes should also be used if the argument contains a
::: batch special character like &, |, etc. so that the special character
::: does not need to be escaped with ^.
:::
::: If called with a single argument of /? then prints help documentation
::: to stdout.
:::
::: Search - By default this is a case sensitive JScript (ECMA) regular
::: expression expressed as a string.
:::
::: JScript syntax documentation is available at
::: http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx
:::
::: Replace - By default this is the string to be used as a replacement for
::: each found search expression. Full support is provided for
::: substituion patterns available to the JScript replace method.
::: A $ literal can be escaped as $$. An empty replacement string
::: must be represented as "".
:::
::: Replace substitution pattern syntax is documented at
::: http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx
:::
::: Options - An optional string of characters used to alter the behavior
::: of REPL. The option characters are case insensitive, and may
::: appear in any order.
:::
::: I - Makes the search case-insensitive.
:::
::: L - The Search is treated as a string literal instead of a
::: regular expression. Also, all $ found in Replace are
::: treated as $ literals.
:::
::: E - Search and Replace represent the name of environment
::: variables that contain the respective values. An undefined
::: variable is treated as an empty string.
:::
::: M - Multi-line mode. The entire contents of stdin is read and
::: processed in one pass instead of line by line. ^ anchors
::: the beginning of a line and $ anchors the end of a line.
:::
::: X - Enables extended substitution pattern syntax with support
::: for the following escape sequences:
:::
::: \\ - Backslash
::: \b - Backspace
::: \f - Formfeed
::: \n - Newline
::: \r - Carriage Return
::: \t - Horizontal Tab
::: \v - Vertical Tab
::: \xnn - Ascii (Latin 1) character expressed as 2 hex digits
::: \unnnn - Unicode character expressed as 4 hex digits
:::
::: Escape sequences are supported even when the L option is used.
:::
::: S - The source is read from an environment variable instead of
::: from stdin. The name of the source environment variable is
::: specified in the next argument after the option string.
:::
::************ Batch portion ***********
#echo off
if .%2 equ . (
if "%~1" equ "/?" (
findstr "^:::" "%~f0" | cscript //E:JScript //nologo "%~f0" "^:::" ""
exit /b 0
) else (
call :err "Insufficient arguments"
exit /b 1
)
)
echo(%~3|findstr /i "[^SMILEX]" >nul && (
call :err "Invalid option(s)"
exit /b 1
)
cscript //E:JScript //nologo "%~f0" %*
exit /b 0
:err
>&2 echo ERROR: %~1. Use REPL /? to get help.
exit /b
************* JScript portion **********/
var env=WScript.CreateObject("WScript.Shell").Environment("Process");
var args=WScript.Arguments;
var search=args.Item(0);
var replace=args.Item(1);
var options="g";
if (args.length>2) {
options+=args.Item(2).toLowerCase();
}
var multi=(options.indexOf("m")>=0);
var srcVar=(options.indexOf("s")>=0);
if (srcVar) {
options=options.replace(/s/g,"");
}
if (options.indexOf("e")>=0) {
options=options.replace(/e/g,"");
search=env(search);
replace=env(replace);
}
if (options.indexOf("l")>=0) {
options=options.replace(/l/g,"");
search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1");
replace=replace.replace(/\$/g,"$$$$");
}
if (options.indexOf("x")>=0) {
options=options.replace(/x/g,"");
replace=replace.replace(/\\\\/g,"\\B");
replace=replace.replace(/\\b/g,"\b");
replace=replace.replace(/\\f/g,"\f");
replace=replace.replace(/\\n/g,"\n");
replace=replace.replace(/\\r/g,"\r");
replace=replace.replace(/\\t/g,"\t");
replace=replace.replace(/\\v/g,"\v");
replace=replace.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
function($0,$1,$2){
return String.fromCharCode(parseInt("0x"+$0.substring(2)));
}
);
replace=replace.replace(/\\B/g,"\\");
}
var search=new RegExp(search,options);
if (srcVar) {
WScript.Stdout.Write(env(args.Item(3)).replace(search,replace));
} else {
while (!WScript.StdIn.AtEndOfStream) {
if (multi) {
WScript.Stdout.Write(WScript.StdIn.ReadAll().replace(search,replace));
} else {
WScript.Stdout.WriteLine(WScript.StdIn.ReadLine().replace(search,replace));
}
}
}
This is going to be clumsy, but if the number of keys to be replaced is limited, the following might be enough for you:
#echo off
set infile=foo.ini
set outfile=newfile.ini
rem create an empty output file
echo. > %outfile%
rem iterate over all properties
for /f " usebackq eol=# tokens=1,2 delims== " %%i in ("%infile%") do (
call :replace %%i %%j
)
rem terminate batch file
goto :eof
rem sub-program to do the replacing
:replace
if "%1"=="Username" (
echo Username=Timmy>>%outfile%
goto :eof
)
if "%1"=="Servername" (
echo Servername=HAL2001>>%outfile%
goto :eof
)
echo %1=%2>>%outfile%
rem terminate sub-program
goto :eof
It may be better to use a tool dedicated to ini files like:
https://github.com/pixelb/crudini

Add text to the End of each File with Notepad++ and Regex

I have 100 files and need to append a line in the end of each single file.
Is there a way how I can do this with Notepad++?
The answer of Lickro is great and works with Notepad++.
Here is a screenshot of the settings:
I am adding a linebreak \n and then the text.
You can search for
(.*)
and replace with
"\1"
with multiline regular expression option activated. In this case (.*) matches whole text in a file and because of the brackets around you can access the match using \1 and append something after that.
suggest you use a batch file
FOR %%G IN (*) DO echo "myline" >> %%G "C:\myDir"
should append myline to all files in myDir

nmake - how to force echo command to output the tab character?

How to force echo command to output a tab character in MS nmake makefile?
Verbatim tabs inserted right into a string after echo command are removed by nmake and don't show up in the output file.
all :
#echo I WANT TO OUTPUT THE <TAB> CHARACTER HERE! > output.txt
You can use a variable with TAB char. Put this lines in your .bat file:
set tab=[stroke TAB char from your keyboard]
echo a%tab%b>yourfile.txt
Doing so, yourfile.txt will have text a[TAB]b
As a workaround, you can create a file containing the tab character, named input.txt (not using nmake), and then say:
all :
#copy /b input.txt output.txt
I assume you already have tried to put the tab inside quotes?
all:
#echo "<TAB>" > output.txt
DOS and Windows have ugly text support in native batch files :).
Here is nice way to do your task:
install Python interpretator
write simple script which appends character with specified code to file
call script wherever you want :)
Simple script:
'''
append_char.py - appends character with specified code to end of file
Usage: append_char.py filename charcode
'''
import os
import sys
filename = sys.argv[1]
assert os.path.exists(filename)
charcode = int(sys.argv[2])
assert 0 <= charcode <= 255
fh = open(filename, 'ab')
fh.seek(0, os.SEEK_END)
fh.write(chr(charcode))
fh.close()
using this script from batch file you can create any possible file in universe :)
output.txt:
<<output.txt
I WANT TO OUTPUT THE <TAB> CHARACTER HERE!
<<KEEP
<TAB> represents a literal tab character here of course.
I had the same need. I used the answer using the quotes around the character and just took it one step further.
{tab} means pressing the keyboard tab key in the text editor.
SET tab="{tab}"
SET tab=%tab:~1,1%
The second line extracts the middle character from the quoted string.
Now you can use the %tab% variable with ECHO and, I suspect, anywhere else it's needed.
ECHO %tab%This text is indented, preceded by a tab.
I suspect this technique could be used with other problem characters as well.