I have an input text file with some server names
I am trying to replace the 'new line' for each server with |.
abcdef.abcdef.abcdef
testing
example
When executed in cmd.exe my script doesn't parse all lines from the input file. Say, if I have 1000 servers in my input file, I can see the output in the Command Prompt window for just around 500 servers.
#echo off
setlocal enableextensions
SETLOCAL EnableDelayedExpansion
rem Purpose - To remove domain name of servers and convert line by line strings to | seperated strings.
type nul > Del_Output.txt
for /f "tokens=1 delims=." %%a in (Downtime.txt) do (
echo(%%a>> Del_Output.txt
)
type Del_Output.txt
rem Initialize the output line
set "line="
rem Catenate all file lines in the same variable separated by "|"
for /F "delims=" %%a in (Del_Output.txt) do set "line=!line!|%%a"
rem Show final line, removing the leading "|"
rem echo !line:~1!>FinalOutput.txt
echo !line:~1!
rem type "C:\Users\AAithal\Desktop\MoogSoft_Downtime\FinalOutput.txt"
ENDLOCAL
Some pointers on the issue would be very helpful.
This should work:
#echo off
setlocal
set "first="
< nul (
for /F "delims=." %%a in (Downtime.txt) do (
if not defined first (
set "first=1"
set /P "=%%a"
) else (
set /P "=|%%a"
)
)
echo/
) > Output.txt
As others have indicated already, the maximum length of a batch variable is 8192 characters, so all names that exceed such a size are not included in your code...
The solution is not use a variable to collect the output. The set /P command allows to output a string with no LF at end, so the input lines are just joined in a long output line.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q56905805.txt"
SET "outline="
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO (
FOR /f "tokens=1*delims=." %%i IN ("%%a") DO IF "%%j"=="" (
SET "outline=!outline!|%%a"
) ELSE (
IF DEFINED outline ECHO !outline!
SET "outline=%%i"
)
)
IF DEFINED outline ECHO !outline!
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances. The listing uses a setting that suits my system.
I used a file named q56905805.txt containing your data for my testing.
The usebackq option is only required because I chose to add quotes around the source filename.
Assign each line to %%a, then reparse it with the delimiter. It it contains the delimiter, it's a new server, so output the previous one and start anew, else accumulate with the required separator.
Related
I am capturing a m3U file on a daily basis but wish to parse part of it to another file with the few channels I need.
For example I have renamed my m3U to Test.txt file which say has the following fictional structure:
#EXTINF:0,ABC
#live link 1
#EXTINF:0,XYZ
#live link 2
#EXTINF:0,UVW
#live link 3
I would just like to capture say the line staring from "#EXTINF:0,XYZ" and say the line beneath it to end up with a Output.txt as follows:
#EXTINF:0,XYZ
#live link 2
I know that one needs to use the For loop but I am a bit of a noob on this area.
Put this code into the file filter.cmd.
#echo off
set INPUT=%1&set MATCH=%2& set MATCHED=0
for /f "delims=" %%a in (%INPUT%) do call :line "%%~a"
goto :eof
:line
set EXT=&TITLE=&
for /f "tokens=1 delims=:" %%a in ("%~1") do set EXT=%%~a
for /f "tokens=1,2,* delims=:," %%a in ("%~1") do set TITLE=%%~c
if "%EXT%" == "#EXTM3U" echo %~1
if "%EXT%" == "#EXTINF" (
set MATCHED=0
echo %TITLE%| findstr /l %MATCH% >nul && set MATCHED=1
)
if %MATCHED%==1 echo %~1
Use example:
filter.cmd input_file.m3u XYZ > output_file.m3u
Here is some explanation:
Every input line is split using for /f with tokens and delims.
MATCHED is set if the line begins with #EXTINF and the rest contains the string to match (second argument).
if MATCHED is set, the lines are output until next #EXTINF.
I would do it like this, supposing the .m3u file does not contain trailing white-spaces in the lines preceded by #EXTINF, like your sample data does:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "FILE=%~1"
set "HEADER=#EXTM3U"
set "PREFIX=#EXTINF"
set "MATCH=%~2"
set "FLAG="
for /F usebackq^ delims^=^ eol^= %%L in ("%FILE%") do (
if defined FLAG (
echo(%%L
set "FLAG="
)
for /F "delims=:" %%P in ("%%L") do (
if "%%P"=="%HEADER%" (
echo(%%L
) else if "%%P"=="%PREFIX%" (
set "LINE=%%L"
setlocal EnableDelayedExpansion
if /I "!LINE:*,=!"=="!MATCH!" (
echo(!LINE!
endlocal
set "FLAG=#"
) else endlocal
)
)
)
endlocal
exit /B
Call the script like this, supposing it is saved as extract-entry.bat:
extract-entry.bat "input_file.m3u" "XYZ" > "output_file.m3u"
The script walks through the given .m3u file line by line. It returns the current line unedited and resets variable FLAG, if variable FLAG is set, which is not the case at the beginning.
Then it looks for #EXTINF. If found (e. g., #EXTINF:0,XYZ), the string after the comma (XYZ) is compared against the given search string. If matched, the current line is output and FLAG variable is set now in order to get the following line too.
The header line #EXTM3U is always output.
Toggling delayed expansion makes this script robust against all characters that have special meaning to the command interpreter without losing them.
how can I remove the duplicate entry from the text file using batch script. All i want to remove the duplicates before "=" sign and "%%" is exist in every single text file. Text file look likes below
%%B05AIPS_CDDOWNLOAD_IBDE_UNC=\\%%B05AIPS_UPLOAD_NODE.\F$\DATA\IPSL\CDFILES\B05_NAG\CD\INCOMING
%%B05AIPS_CDDOWNLOAD_FTS_UNC=\\%%B05AIPS_UPLOAD_NODE.\B05_NAG\FTS\To_Clearpath\%%DATE_CCYYMMDD.
%%B05AIPS_CDDOWNLOAD_FTS_UNC=%%B05AIPS_CDDOWNLOAD_FTS_UNC.
I got about 30 plus different text files which contains above kind of entries and want to remove the duplicate line and want to keep the first occurrence. Remember duplicate line should be identified before "=" sign only and removal required for the entire line.Each of the different text files have got "%%" sign. Please guide me if there is way to do through batch script or vbscript? Thanks
Here is a simple batch-file solution; let us call the script rem-dups.bat. Supposing your input file is test.txt and your output file is result.txt, you need to provide these files as command line arguments, so you need to call it by: rem-dups.bat "test.txt" "results.txt". Here is the script:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "INFILE=%~1"
set "OUTFILE=%~2"
if not defined INFILE exit /B 1
if not defined OUTFILE set "OUTFILE=con"
for /F "usebackq tokens=1,* delims==" %%K in ("%INFILE%") do (
set "LEFT=%%K"
set "RIGHT=%%L"
set "LEFT=!LEFT:*%%%%=__!"
rem Remove `if` query to keep last occurrence:
if not defined !LEFT! set "!LEFT!=!RIGHT!"
)
> "%OUTFILE%" (
for /F "delims=" %%F in ('set __') do (
set "LINE=%%F"
echo(!LINE:*__=%%%%!
)
)
endlocal
exit /B
The script is based on the fact that there cannot occur duplicate environment variables, that are such with equal names.
This code only works if the following conditions are fulfilled:
the file content is treated in a case-insensitive manner;
the order of lines in the output file does not matter;
the partial strings before the first = sign start with %% and contain at least one more character other than %;
the partial strings before the first = contain only characters which may occur within environment variable names, besides the leading %%;
the partial strings after the first = must not be empty;
the partial strings after the first = must not start with = on their own;
no exclamation marks ! are allowed within the file, because they may get lost or lead to other unexpected results;
Here is an alternative method using a temporary file:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "INFILE=%~1"
set "OUTFILE=%~2"
if not defined INFILE exit /B 1
if not defined OUTFILE set "OUTFILE=con"
set "TEMPFILE=%TEMP%\%~n0_%RANDOM%.tmp"
> "%TEMPFILE%" break
> "%OUTFILE%" (
for /F usebackq^ delims^=^ eol^= %%L in ("%INFILE%") do (
for /F tokens^=1^,*^ delims^=^=^ eol^= %%E in ("%%L") do (
> nul 2>&1 findstr /I /X /L /C:"%%E" "%TEMPFILE%" || (
echo(%%L
>> "%TEMPFILE%" echo(%%E
)
)
)
)
> nul 2>&1 del "%TEMPFILE%"
endlocal
exit /B
Every unique (non-empty) token left to the first = sign is written to a temporary file, which is searched after having read each line from the input file. If the token is already available in the temporary file, the line is skipped; if not, it is written to the output file.
The file content is treated in a case-insensitive manner, unless you remove the /I switch from the findstr command.
Update: Improved Scripts
Here are two scripts which are improved so that no special character can bring them to fail. They do not use temporary files. Both scripts remove lines with duplicate keywords (such is the partial string before the first = sign).
This script keeps the first line in case of duplicate keywords have been encountered:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "INFILE=%~1"
set "OUTFILE=%~2"
if not defined INFILE exit /B 1
if not defined OUTFILE exit /B 1
> "%OUTFILE%" break
for /F usebackq^ delims^=^ eol^= %%L in ("%INFILE%") do (
for /F tokens^=1^ delims^=^=^ eol^= %%E in ("%%L") do (
set "LINE=%%L"
set "KEY=%%E"
setlocal EnableDelayedExpansion
if not "!LINE:~,1!"=="=" (
set "KEY=!KEY: = !"
set "KEY=!KEY:\=\\!" & set "KEY=!KEY:"=\"!"
more /T1 "%OUTFILE%" | > nul 2>&1 findstr /I /M /B /L /C:"!KEY!=" || (
>> "%OUTFILE%" echo(!LINE!
)
)
endlocal
)
)
endlocal
exit /B
This script keeps the last line in case of duplicate keywords have been encountered:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "INFILE=%~1"
set "OUTFILE=%~2"
if not defined INFILE exit /B 1
if not defined OUTFILE exit /B 1
> "%OUTFILE%" (
for /F delims^=^ eol^= %%L in ('findstr /N /R "^" "%INFILE%"') do (
set "LINE=%%L"
for /F "delims=:" %%N in ("%%L") do set "LNUM=%%N"
setlocal EnableDelayedExpansion
set "LINE=!LINE:*:=!"
if defined LINE if not "!LINE:~,1!"=="=" (
for /F tokens^=1^ delims^=^=^ eol^= %%E in ("!LINE!") do (
setlocal DisableDelayedExpansion
set "KEY=%%E"
setlocal EnableDelayedExpansion
set "KEY=!KEY: = !"
set "KEY=!KEY:\=\\!" & set "KEY=!KEY:"=\"!"
more /T1 +!LNUM! "%INFILE%" | > nul 2>&1 findstr /I /M /B /L /C:"!KEY!=" || (
echo(!LINE!
)
endlocal
endlocal
)
)
endlocal
)
)
endlocal
exit /B
For both scripts, the following rules apply:
the order of lines with non-duplicate keywords is maintained;
empty lines are ignored and therefore removed;
empty keywords, meaning lines starting with =, are ignored and therefore removed;
non-empty lines that do not contain an = at all are treated as they would be ended with an = for the check for duplicates, hence the entire line is used as the keyword;
for the check for duplicates, each TAB character is replaced by a single SPACE;
every line that is transferred to the returned file is copied from the original file without changes (hence the aforementioned attachment of = or replacement of TAB is not reflected there);
the check for duplicates is done in a case-insensitive manner, unless you remove the /I switch from the findstr command;
Amendment: Processing Multiple Files
All of the above scripts are designed for processing a single file only. However, if you need to process multiple files, you could simply write a wrapper that contains a for loop enumerating all the input files and calls one of the scripts above (called rem-dups.bat) for every item -- like this:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Define constants here:
set "INPATH=D:\Data\source" & rem (location of input files)
set "OUTPATH=D:\Data\target" & rem (location of output files)
set INFILES="source.txt" "test*.txt" & rem (one or more input files)
set "OUTSUFF=_no-dups" & rem (optional suffix for output file names)
set "SUBBAT=%~dp0rem-dups.bat"
pushd "%INPATH%" || exit /B 1
for %%I in (%INFILES%) do if exist "%%~fI" (
call "%SUBBAT%" "%%~fI" "%OUTPATH%\%%~nI%OUTSUFF%%%~xI"
)
popd
endlocal
exit /B
You must not specify the same locations for the input and output files. If you want to overwrite the original input files, you need to write the modified output files to another location first, then you can move them back to the source location -- supposing you have set OUTSUFF in the wrapper script to an empty string (set "OUTSUFF=" instead of set "OUTSUFF=_no-dups"). The command line to overwrite the original input files would be: move /Y "D:\Data\target\*.*" "D:\Data\source".
You could read the file into Excel without splitting it into multiple columns. Use Excel functionality to eliminate duplicates and save it back. You could do all this in VBScript.
Create an Excel Object
Loop
Load text file
Remove duplicates
Save text file
Until there are no more files
Dispose of the Excel Object
Code for the individual pieces should be easily available on the web. Do ask for any additional, specific, pointers you might need.
I want to be able to replace a line in a properties file but i only know part of the line string at any one time
Heres the line i want to replace: mb.datasource.password=ENC(8dF45fdD)
with this: mb.datasource.password=apassword
What i have just now is this
#echo off &setlocal
set "search=mb.datasource.password="
set "replace=mb.datasource.password=apassword"
set "textfile=mb.properties"
set "newfile=mb-new.properties"
(for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
))>"%newfile%"
This ends up giving me mb.datasource.password=apassword=ENC(8fFdeUdK)
I can't just find the full string it needs to only be mb.datasource.password= because the part after the equals changes
Any help would be greatly appreciated?
You can do it with batch. I put together a quick script and it worked for me:
#ECHO OFF
SETLOCAL EnableExtensions
SET SourceFile="mb.properties"
SET OutputFile="mb-new.properties"
SET "FindKey=mb.datasource.password"
SET "NewValue=apassword"
REM Basic parse for INI file format.
(FOR /F "usebackq eol= tokens=1,* delims==" %%A IN (`TYPE %SourceFile%`) DO (
REM If the key value matches, build the line with the new value.
REM Otherwise write out the existing value.
IF /I "%%A"=="%FindKey%" (
ECHO %%A=%NewValue%
) ELSE (
ECHO %%A=%%B
)
)) > %OutputFile%
REM Replace old with new.
DEL %SourceFile%
MOVE %OutputFile% %SourceFile%
ENDLOCAL
A few notes about the above:
I assumed basic INI file format.
The FOR loop will skip blank lines so they would be removed from the new output file. There are ways around this using tricks with the FIND command if the blanks are needed.
If you have special chars (% or ! especially) - this may cause some problems, but if you have just "normal" text then it should be fine.
I want to find a word in a text file using a batch file and then I want to remove that line containing the word and also delete some other lines below for example:
_italic_ or **bold**
put returns between paragraphs
indent code by 4 spaces
indent code by 4 spaces
_italic_ or **bold**2
so the result should be:
_italic_ or **bold**
_italic_ or **bold**2
You can try this batch code:
#echo off
set skipline=2
set search=returns
set File=Input.txt
setlocal EnableDelayedExpansion
for %%a in ("%File%") do (
set linecount=1
set skip=0
For /f "usebackq tokens=* delims=" %%b IN (`type "%%a" ^| find /V /N ""`) do (
set a=%%b
set a=!a:*]=!
if "!a!" NEQ "" (
set search=!a:%search%=!
if "!search!" NEQ "!a!" set /a skip=%skipline%+!linecount!
)
if !linecount! GTR !skip! echo(!a!
set /a linecount+=1
)>>tmp
move /Y "tmp" "%%a">Nul
)
EndLocal
exit
This is working with a file containing blank lines and multiple line.
Change set skipline=2 for how many line to skip after find a word you search.
And for multiple files just change set File=Input.txt.
Example for file with extension .txt in current directory:
set File=*.txt
#echo off
setlocal EnableDelayedExpansion
rem Get the number of lines before the one that contain "returns"
for /F "delims=:" %%a in ('findstr /N "returns" input.txt') do set /A "lines=%%a-1"
rem Open a code block to read from input.txt and write to output.txt
< input.txt (
rem Read and write the first "lines" lines
for /L %%i in (1,1,%lines%) do (
set "line="
set /P "line="
echo(!line!
)
rem Omit the number of desired lines (3 in this example)
for /L %%i in (1,1,3) do set /P "line="
rem Copy the rest of lines
findstr "^"
) > output.txt
rem Replace the original file by the new one
move /Y output.txt input.txt
Here is a batch code for this task working only for an input text file not containing empty lines as those lines are skipped by command FOR.
It removes all blocks with 3 lines whereby first line contains returns.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "SkipLineCount=0"
set "OutputFile=OutputTextFile.txt"
del "%OutputFile%" 2>nul
for /F "usebackq eol=^ delims=" %%I in ("InputTextFile.txt") do (
if !SkipLineCount! EQU 0 (
set "Line=%%I"
set "Line=!Line:returns=!"
if "!Line!" NEQ "%%I" ( set "SkipLineCount=1" ) else echo(%%I>>"%OutputFile%"
) else (
set /A SkipLineCount+=1
if !SkipLineCount! EQU 3 set "SkipLineCount=0"
)
)
move /Y "%OutputFile%" "InputTextFile.txt"
endlocal
This batch file processes each non empty line. Command FOR skips automatically all lines not containing any character.
Note 1: eol=^ in line with command FOR is necessary to read in and output also lines just containing commas or semicolons which otherwise would be also ignored by command FOR.
The current line is assigned to variable Line if currently no lines should be skipped. Next all occurrences of the word returns are removed case-insensitive from the line if the line contains at least one returns.
The line is ignored if the string of variable Line is not equal after the string replace with unmodified line read from file because this means the line contains at least one returns.
Otherwise the line read from input file is appended to output file.
Note 2: ( between echo and %%I is used here to output also input lines containing only 1 or more spaces or tabs as otherwise with a space instead of ( the command echo would write for such a case its current state OFF into the output file instead of the spaces/tabs read from input file.
The next 2 lines after a line with at least one returns are also ignored for being copied to output file.
As last command the created output file with the 3 lines removed is moved over the input text file.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
for /?
if /?
move /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators.
I am creating a code that strips through different MAC addresses randomly, but cannot figure out how to do this. My thought on how to approach this is to randomize or rearrange the order of the MAC address in the text file with this script, but I cannot figure out how to do this with a batch file. How this will work is that it will read "maclist.txt", then create a new temp file with the random order "maclist_temp.txt", that will be the rearranged file. Then, it will pull this randomized file in order.
I have tried Google and searching the web, but I haven't found anything too useful. I'm still actively looking, but any advice would be extremely useful.
Something as simple as extracting and deleting a random line and then adding to the bottom might work. Randomization would be better though, but I want to keep the original list. Something like:
Make a temp copy of maclist.txt called maclist_temp.txt
Take one random MAC address, remove it from maclist_temp.txt
Readd it to the bottom
That is all I want, but any suggestions are welcome.
You may try this batch file to help you to shuffle your maclist.txt. The usage of the batch code is
C:\> type list.txt | shuffle.bat > maclist_temp.txt
Here are the contents of shuffle.bat:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET TmpFile=tmp%RANDOM%%RANDOM%.tmp
TYPE NUL >%Tmpfile%
FOR /F "tokens=*" %%i IN ('MORE') DO SET Key=!RANDOM!!RANDOM!!RANDOM!000000000000& ECHO !Key:~0,15!%%i>> %TmpFile%
FOR /F "tokens=*" %%i IN ('TYPE %TmpFile% ^| SORT') DO SET Line=%%i&ECHO.!Line:~15!
::DEL %TmpFile%
ENDLOCAL
After issuing the above command, maclist_temp.txt will contain a randomized list of MAC addresses.
Hope this helps.
Here is a simpler method to randomize/randomise a file, no temp files needed. You can even reuse the same input filename.
Limitations are: blank lines and line starting with ; will be skipped, and lines starting with = will have all leading = signs stripped and ^ characters are doubled.
#echo off
setlocal
for /f "delims=" %%a in (maclist.txt) do call set "$$%%random%%=%%a"
(for /f "tokens=1,* delims==" %%a in ('set $$') do echo(%%b)>newmaclist.txt
endlocal
I really like foxidrive's approach. Nevertheless I want to provide a solution with all the listed limitations eliminated (although cmd-related restrictions like file sizes < 2 GiB and line lengths < ~ 8 KiB remain).
The key is delayed expansion which needs to be toggled to not lose explamation marks. This solves all the potential problems with special characters like ^, &, %, !, (, ), <, >, | and ".
The counter index has been implemented in order not to lose a single line of the original text file, which could happen without, because random may return duplicate values; with index appended, the resulting variable names $$!random!.!index! are unique.
The findstr /N /R "^" command precedes every line of the original file with a line number followed by a colon. So no line appears empty to the for /F loop which would ignore such. The line number also implicitly solves the issue with leading semicolons, the default eol character of for /F.
Finally, everything up to and including the first colon (remember the said prefix added by findstr) is removed from every line before being output, hence no more leading equal-to signs are dismissed.
So here is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set /A "index=0"
for /f "delims=" %%a in ('findstr /N /R "^" "%~dpn0.lst"') do (
setlocal EnableDelayedExpansion
for /F %%b in ("$$!random!.!index!") do (
endlocal
set "%%b=%%a"
)
set /A "index+=1"
)
> "%~dpn0.new" (
for /f "delims=" %%a in ('set $$') do (
set "item=%%a"
setlocal EnableDelayedExpansion
echo(!item:*:=!
endlocal
)
)
endlocal
exit /B
This seems to work. Feed it a command line parameter of the file to randomize.
#echo off
setlocal EnableDelayedExpansion
rem read the number of lines in the file
rem the find prepends the line number so we catch blank lines
for /f "delims=" %%n in ('find /c /v "" %1') do set "len=%%n"
set len=!len:*: =!
rem echo %1 has %len% lines
rem Relocate as many lines as there are lines in the file
for /l %%j in (1 1 !len!) do (
rem echo starting round %%j
rem geta random number between 1 and the number of lines in the file
set /a var=!random! %% !len! + 1
rem echo relocating line !var!
rem make sure there is no temp file
if exist %1.temp del %1.temp
rem read each line of the file, write any that don't match and then write the one that does
<%1 (
for /l %%i in (1 1 !len!) do (
rem if it is the target line then save it
if %%i == !var! (
set /p found=
rem echo saving !found!
)
rem if it is the target line then write it
if not %%i == !var! (
set /p other=
rem echo writing !other!
echo !other!>> %1.temp
)
)
rem now write the target line at the end
rem echo appending !found!
echo !found!>> %1.temp
)
rem replace the original with the temp version
move %1.temp %1>nul
)
rem print the result
type %1
Place in cmd file
for /f "tokens=2 delims=/" %%m in ('cmd /e:on /v:on /c "for /f %%f in (maclist.txt) do #echo !random!/%%f" ^| sort') do echo %%m
It spawns a cmd which reads the mac list in the inner for, prefixes a random value and a slash to the mac and sorts the list. Then this list is splitted in the outter for using the slash as delimiter and printing the mac address.