Stopping when a string has been found - batch-file

Hello StackOverflow community!
I have a BATCH question that has been plaguing me for a few days now:
I am trying to do a sting comparison (sounds simple) but I am doing it in this manner:
I have two Folders: SESSIONS and TARGETS.
Each of these folders has a ordinary text files that have been named after a server: Server1.txt, Server2.txt, Server3.txt, etc. Both directories have files with exactly the same names. The file names are important only because after reading them, I will know where to allocate the information that is contained in that file. Example:
SESSIONS-->Server1.txt
Word_one
Word_two
Word_three
word_seven
TARGETS-->Server1.txt
Word_one
Word_two
Word_seven
This is the code that i am using to traverse the Sessions and Targets folders:
FOR %%a in (%ses_dir%*.txt) DO (
FOR /F "TOKENS=1 DELIMS= " %%c in (%%a) DO (
FOR %%f in (%targ_dir%*.txt) DO (
FOR /F "TOKENS=1 DELIMS= " %%i in (%%f) DO (
SET tmp_nam=%%~na
IF %%c EQU %%i ( ECHO This is Connected)
IF %%c NEQ %%i ( ECHO This is not Connected)
)
)
)
)
The above will print out all the sessions that are connected and all the sessions that are not connected. Essentially, this will output a LOT of redundant and useless information. I would like it to do the following:
Every time it finds a string from the first file in the second file, Stop right there, and move onto the next string in the first file.
If it does not find the string from the first file in the second file. Echo "String not found" or something along those lines.
I have tried to be as descriptive as I could. Let me know if you have any additional questions.
Thank you in advance!

This can be done with the built-in associative arrays of the Batch language:
#echo off &SETLOCAL
SET "sessionDir=SESSIONS"
SET "targetDir=TARGETS"
FOR %%a IN ("%sessionDir%\*.txt") DO (
IF NOT EXIST "%targetDir%\%%~nxa" (
ECHO "%%~nxa" NOT found IN "%targetDir%"
) ELSE (
FOR /f "usebackqdelims=" %%b IN ("%%~fa") DO SET "$%%b=1"
FOR /f "usebackqdelims=" %%b IN ("%targetDir%\%%~nxa") DO SET "#%%b=1"
FOR /f "delims=$=" %%x IN ('set "$"') DO IF NOT DEFINED #%%x ECHO "%%x" missing IN "%targetDir%\%%~nxa"
FOR /f "delims=#=" %%x IN ('set "#"') DO IF NOT DEFINED $%%x ECHO "%%x" missing IN "%%~fa"
)
)
Please note: the Word_ items can't have = signs, leading or trailing space.

FOR %%a in (%ses_dir%*.txt) DO (
FOR /F "TOKENS=1 DELIMS= " %%c in (%%a) DO (
SET "tmp_nam="
FOR /F "TOKENS=1 DELIMS= " %%i in (%targ_dir%%%~nxa) DO IF NOT DEFINED tmp_nam (
IF %%c EQU %%i SET tmp_nam=%%~na
)
if defined tmp_nam (echo %%c connected) else (echo %%c not connected)
)
)
This should, I believe, achieve your end.
%%a is set to each session's textfilename in turn.
%%c is set to each word from the textfile in %%a and tmp_nam is cleared
%%i is set to each word from the identical filename in the targets directory.
If a match is found, tmp_nam is set to something (it doesn't matter what, just not empty) The remainder of the comparisons to the remaining words in targets are skipped because tmp_nam is now defined.
Depending on whether a match was found or not, the word that matched + "(not) connected" is output. Could just as easily be %%a or both %%c and %%a if that floats your boat.
Now - if you mean that you want to say %%a (not) connected if ANY ONE word in the session is matched in targets, regardless,
FOR %%a in (%ses_dir%*.txt) DO (
SET "tmp_nam="
FOR /F "TOKENS=1 DELIMS= " %%c in (%%a) DO (
FOR /F "TOKENS=1 DELIMS= " %%i in (%targ_dir%%%~nxa) DO IF NOT DEFINED tmp_nam (
IF %%c EQU %%i SET tmp_nam=%%~na
)
)
if defined tmp_nam (echo %%a connected) else (echo %%a not connected)
)
which is simply moving the reporting out one level.

Related

Calling a function for every attribute I want to read from multiple .txt files and write to .csv file

I tried to call a function for every attribute (column) that I want to read from 4 .txt files and then write into a .csv file. One column has flawed output and the code should have a few logic flaws as I haven't learned batch cleanly from scratch. Do you know a fix?
Link to previous solved question: Read information from multiple .txt files and sort it into .csv file
#Magoo
echo Name;Prename;Sign;Roomnumber;Phonenumber > sorted.csv
for /f "tokens=1,2 delims= " %%a in (TestEmployees.txt) do (
call :findSign %%a %%b
)
:findSign
set prename=%1
set name=%2
for /f "tokens=1,2 delims= " %%a in (TestSign.txt) do (
if "%name%"=="%%a" (
call :findRoomNumber
)
)
:End
:findRoomNumber
set sign=%1
for /f "tokens=1,2 delims=|" %%q in (TestRoomNumber.txt) do (
if "%sign%"=="%%q" (
call :findPhoneNumber
)
)
:End
:findPhoneNumber
for /f "tokens=1,2 delims=;" %%u in (TestPhoneNumber.txt) do (
if "%%b"=="%%u" (
echo %name%;%prename%;%%b;%%r;%%v >> sorted.csv
)
)
:End
This is the way I would do it:
#echo off
setlocal EnableDelayedExpansion
rem Load PhoneNumber array
for /F "tokens=1,2 delims=;" %%a in (PhoneNumber.txt) do set "phone[%%a]=%%b"
rem Load RoomNumber array
for /F "tokens=1,2 delims=|" %%a in (RoomNumber.txt) do set "room[%%a]=%%b"
rem Load Sign array
for /F "tokens=1,2" %%a in (Sign.txt) do set "sign[%%a]=%%b"
rem Process Employees file and generate output
> sorted.csv (
echo Name;Prename;Sign;RoomNumber;PhoneNumber
for /F "tokens=1,2" %%a in (Employees.txt) do for %%s in (!sign[%%b]!) do (
echo %%b;%%a;%%s;!room[%%s]!;!phone[%%s]!
)
)
#ECHO OFF
SETLOCAL
rem The following settings for the directories and filenames are names
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
SET "filename1=%sourcedir%\q74258020_TestEmployees.txt"
SET "filename2=%sourcedir%\q74258020_TestSign.txt"
SET "filename3=%sourcedir%\q74258020_TestRoomNumber.txt"
SET "filename4=%sourcedir%\q74258020_TestPhoneNumber.txt"
SET "outfile=%destdir%\outfile.txt"
>"%outfile%" (
echo Surname;Name;Sign;Roomnumber;Phonenumber
for /f "usebackqtokens=1,2 delims= " %%g in ("%filename1%") do (
call :findSign %%g %%h
)
)
GOTO :eof
:findSign
for /f "usebackqtokens=1,2 delims= " %%b in ("%filename2%") do (
if "%2"=="%%b" (
for /f "usebackqtokens=1,2 delims=|" %%q in ("%filename3%") do (
if "%%c"=="%%q" (
for /f "usebackqtokens=1,2 delims=;" %%u in ("%filename4%") do (
if "%%c"=="%%u" (
echo %2;%1;%%c;%%r;%%v
)
)
)
)
)
)
GOTO :EOF
Always verify against a test directory before applying to real data.
Note that if the filename does not contain separators like spaces, then both usebackq and the quotes around %filename1% can be omitted.
Why should I not upload images of code/data/errors? Copy and paste the code as text
For similar reasons, please post all relevant data into a question to obviate every potential respondent having to switch back and forth to the data to which you have linked.

IS this possible to modify multiple variable from same file using a .batch file without effecting other things like space, special char?

I have a file rev.ini having multiple variable to update:
s1=10
s2=20
s3=30
Here I am using separate loop for finding string in a file. there are 3 times loop are running for same file. Is it possible to find these three string in same loop?
#Echo Off
cd /d D:\xyz
setlocal enabledelayedexpansion
set s1=10
set s2=11
set s3=12
set "file=rev.ini"
for /F "tokens=1,* delims==" %%i in ('findstr "s1= " rev.ini') do (
set "versionVar=%%~i"
set "versionVal=%%~j"
set sequence=%s1%
)
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>%file%') do (
set "line=%%j"
if "!line!" == "!versionVar!=!versionVal!" set line=!versionVar!=!sequence!
echo(!line!>>!file!
)
for /F "tokens=1,* delims==" %%i in ('findstr "s2= " rev.ini') do (
set "versionVar=%%~i"
set "versionVal=%%~j"
set sequence=%s2%
)
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>%file%') do (
set "line=%%j"
if "!line!" == "!versionVar!=!versionVal!" set line=!versionVar!=!sequence!
echo(!line!>>!file!
)
for /F "tokens=1,* delims==" %%i in ('findstr "s3= " rev.ini') do (
set "versionVar=%%~i"
set "versionVal=%%~j"
set sequence=%s3%
)
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>%file%') do (
set "line=%%j"
if "!line!" == "!versionVar!=!versionVal!" set line=!versionVar!=!sequence!
echo(!line!>>!file!
)
Goto :EOF
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory and filename are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "filename1=%sourcedir%\q74276740.txt"
SET "outfile=outfile.txt"
set "s1=10"
set "s2=11"
set "s3=12"
REM (
FOR /f "usebackqtokens=1*delims==" %%b IN ("%filename1%") DO (
SET "#keep=Y"
FOR /f "tokens=1*delims==" %%u IN ('set') DO (IF /i "%%b"=="%%u" SET "#keep="&ECHO %%b=%%v)
IF DEFINED #keep IF "%%c"=="" (ECHO %%b) ELSE (ECHO %%b=%%c)
)
REM )>"%outfile%"
GOTO :EOF
Always verify against a test directory before applying to real data.
Note that if the filename does not contain separators like spaces, then both usebackq and the quotes around %filename1% can be omitted.
Simply read each line. If the line contains = and the part before the = contains any variablename in the environment (I made it case-insensitive with /i) then generate a line using the matching value. If #keep remains set after the for..%%u has been executed, then there is no match, so either reproduce the original x=y or the original line, if it had no =.
The output file can be generated by removing the rem before the ( and ).
The output file must be different from the input file, and should be moved over the input file when the batch finishes (not shown)
--- After comment ---
So, if you follow the instructions provided in the last two paragraphs, you get
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory and filename are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "filename1=%sourcedir%\q74276740.txt"
SET "outfile=outfile.txt"
set "s1=10"
set "s2=11"
set "s3=12"
(
FOR /f "usebackqtokens=1*delims==" %%b IN ("%filename1%") DO (
SET "#keep=Y"
FOR /f "tokens=1*delims==" %%u IN ('set') DO (IF /i "%%b"=="%%u" SET "#keep="&ECHO %%b=%%v)
IF DEFINED #keep IF "%%c"=="" (ECHO %%b) ELSE (ECHO %%b=%%c)
)
)>"%outfile%"
move "%outfile%" "%filename1%"
GOTO :EOF
== revision of processing section in light of new requirement to retain empty lines ==
REM (
FOR /f "tokens=1,2*delims=:=" %%g IN ('findstr /n ^^^^ "%filename1%"') DO IF "%%h"=="" (ECHO.) ELSE (
SET "#keep=Y"
FOR /f "tokens=1*delims==" %%u IN ('set') DO (IF /i "%%h"=="%%u" SET "#keep="&ECHO %%h=%%v)
IF DEFINED #keep IF "%%i"=="" (ECHO %%h) ELSE (ECHO %%h=%%i)
)
REM )>"%outfile%"
Once again, the rem keywords need to be removed to output to the nominated file.
The changes simply feed the file through a findstr command which produces a listing of the file with a prefix of linenumber:. The extra : in the delims causes the line number to be parsed to %%g. I've changed the metavariable letters because three are required for the processing, and I prefer to not use letters that are also modifiers.
If findstr produces only a line number then it was a blank line, so %%h will be empty and we simply produce an empty line, otherwise, processing as before.

Locating keyword in .csv files

I am trying to create batch file that reads specific CSV documents from specific file, and extracts some lines that have specific number and print it out on the screen " the whole line !". The problem is I created the code but it wont work at all, whenever I tried it only prints the line numbers!?
The code:
#echo off
setlocal EnableDelayedExpansion
set "yourDir=C:\Users\Adminm\Desktop\test11\"
set "yourExt=csv"
set "keyword=44"
set /a count=0
set linenum=!count!
set c=0
pushd %yourDir%
for %%a in (*.%yourExt%) do (
for /f "usebackq tokens=3 delims=," %%b in (%yourDir%%%a) do (
set /a count = !count! + 1
if NOT %%b == %keyword% (
for /f "delims=" %%1 in ('type %yourDir%%%a') do (
set /a c+=1 && if "!c!" equ "%linenum%" echo %%1%
)
)
)
)
echo !count!
popd
endlocal
thanks in advance <3
for %%a in (*.%yourExt%) do (
for /f "usebackq delims=" %%L in ("%%a") do (
for /f "tokens=3 delims=," %%b in ("%%L") do (
if %%b == %keyword% echo %%L
)
)
)
Assuming what you want to do is scan each file for a target string in column3, then:
Since you have already changed to yourdir, there's no requirement to specify it in the scan-for-filenames for.
Your attempt to locate the required line is clumsy. All you need to do is assign each line in turn to a metavariable (%%L) and then use for/ to parse the metavariable. When the required data matches, simply echo the metavariable containing the entire line.
You've attempted to use %%1 as a metavariable. %n for n=0..9 refers to the parameter number supplied to the routine. The only officially defined metavariables for use here are %%a..%%z and %%A..%%Z (one of the very few places where batch is case-sensitive) - although some other symbols also work. Numerics will not work here.

Removing part of filename with batch

I've tried to tweak a lot of the code provided to similar questions, but I don't think the solution is posted. My problem is that the part from where I want to remove the rest exists 2 times before the last!
What I have is a folder with:
number1-number2-number3 - some random text about the file.filetype
number1 will range from 01 to 99
number2 will range from 1-99999
number3 will range from 1-999 with the possibility of 2 decimals, separated from whole number by .
Example folder c:\temp\:
15-1592-1 - file 1.doc
15-1592-2 - this is file2.pdf
15-1592-3 - this cointains subfiles.html
15-1592-3.1 - sub1.jpg
15-1592-3.2 - sub2.pdf
What I need is a folder where everything after the end of number3 is removed from the filename, but also the file type unaltered.
Example:
15-1592-1.doc
15-1592-2.pdf
15-1592-3.html
15-1592-3.1.jpg
I understand this is quiet possible from reading all the answers combined.
What I lack is the knowledge to compile it all!
You want to delete everything after the first space (without the extension)
This is quite easy, if you use modifiers (see for /?):
#echo off
setlocal enabledelayedexpansion
for %%a in (??-*-*) do (
for /f "tokens=1 delims= " %%b in ("%%~na") do (
ECHO ren "%%a" "%%b%%~xa"
)
)
its' a little bit tricky to extract the decimal part (if present), but this should do the job (may need some token adjustment to fit your needs)
#echo off
setlocal enabledelayedexpansion
set "source_path=c:\temp\*"
for /f "tokens=1,* delims=." %%a in ('dir /b %source_path%') do (
set "ext=" & set "decimal="
for /f "tokens=1,* delims=." %%i in ("%%b") do (
if "%%j" neq "" (
set "ext=%%j"
for /f "tokens=1,* delims=- " %%d in ("%%i") do set "decimal=.%%d"
) else (
set "ext=%%i"
)
)
for /f "tokens=1-3,* delims=- " %%i in ("%%a") do (
rem replace echo with operation you need
echo %%i-%%j-%%k!decimal!.!ext!
)
)
endlocal

How do I only assign FOR /F token from one line only in a test file?

How do I make this grab the token from the first line ONLY in .txt file instead of looping through every line. I want %%m to be assigned to the 3rd token on line one only then stop.
#echo off
FOR %%A IN (.\xdrive\*.txt) DO (
FOR /F "usebackq tokens=3 delims=," %%m IN ("%%A") DO (
IF "%%m" == "F01" (xcopy /Y "%%A" .\Outbound)
pause
)
)
pause
set /p can be used to read the first line, and then you can use a FOR /F loop to get the third token
setlocal EnableDelayedExpansion
FOR %%A IN (%1) DO (
<%%A set /p firstline=
FOR /F "tokens=3 delims=," %%m IN ("!firstline!") DO (
echo %%m
)
)
Without see the eg files and knowing exactly what you're trying to do I can't test this, but here's the listing of firstline.bat which should do what you're asking for :) At first I thought this needed to be more complicated than it is... after your first if simply use a goto to exit the for structure after it's first call - problem solved?
#echo off
::: firstline.bat - Retrieve the first line from a series of files
::: usage: firstline $filespec
::: filespace - files to process (eg .\xdrive\*.txt)
if "%~1"=="" findstr "^:::" "%~f0"&GOTO:EOF
FOR %%A IN (%1) DO (
call :testfirst "%%A"
)
goto :eof
:testfirst
FOR /F "usebackq tokens=3 delims=," %%m IN (%1) DO (
IF "%%m" == "F01" (xcopy /Y %1 .\Outbound)
goto:eof
)
See this post, which shows how to mimic the gnu head utility using a dos batch file:
Windows batch command(s) to read first line from text file
untested
read first line tokens3
for /f "tokens=3 delims=," %%a in ('"findstr /n . %1|findstr /b 1:"') do set fltok3=%%a
echo(%fltok3%
Hackish =
#echo off
FOR %%A IN (.\xdrive\*.txt) DO (
FOR /F "usebackq tokens=3 delims=," %%m IN ("%%A") DO (
IF "%%m" == "F01" (xcopy /Y "%%A" .\Outbound)
GOTO:EOF
)
)
So all you're doing is escaping the loop after the first pass instead of continuing onto the next line.

Resources