Batch - For /F with IF/File/Comparison - batch-file

Dears,
I'm hoping you can help me, because I lost my faith.
Let me show you what I have done, and then explain what I need to achive.
#echo off
echo "Which Site do you want to check?"
set /p ans="Site: "
echo.
for /f "tokens=1,2,3 delims=," %%A IN (animals.csv) DO if %%A==%ANS% (ping %%B AND ping %%C)
echo.
pause
echo.
cls
goto menu
User should put something animal name which will be stored in ANS variable.
Script should check in animals.csv what IP adresses are assigned for that animal.
After matching, script should ping IP adresses in next columns, so user could see results.
PS: All both files are in the same folder.
Problem is that animals.txt has 3 columns and a lot of records.
I was able make script work till point of comparing variables, then I stopped working.
Let's say that animals file looks like that:
cat,111.111.111.111,122.122.122.122
dog,222.222.222.222,233.233.233.233
horse,333.333.333.333,344.344.344.344
Help me, because I stuck and I have no damn clue how to do it.

Your script works, when you replace AND with & (see SS64.com)
But let me suggest a slightly different logic:
#echo off
echo "Which Site do you want to check?"
set /p ans="Site: "
echo.
for /f "tokens=1,2,3 delims=," %%A IN ('type animals.csv^|findstr /b "%ans%,"') DO (
ping %%B
ping %%C
)
echo.
pause
findstr parameter /b means "string should start with" - prevents maddog to be recognized as dog.
The trailing comma in the searchstring prevents catfish to be recognized as cat.
You might want to add /i to make the search case-insensitive (cat and Cat will be recognized).

Related

pulling a variable from text file in a sentence

im currently making something along the lines of a sentence generator, it uses text files which have a list of words in them, for example celebrity.txt has a list of celebrities and this script both shuffles the text file into newcelebrity.txt and takes the first one from that list so its different every time, and ive run into a problem, i want it to be one line and that you can call a variable in the sentance youre typing, not break it down as it is right now, is there a way to have it "this $celebrity is really great" as of now, it works like this: https://gyazo.com/9ae8583ed5457709bd1c1dc9cc0cc106 and outputs as this https://gyazo.com/1a5a90f1fbf80faa73d71791a8c1c761, i dont mind the quotation marks at all, its just the way you input it.
Is there any way to make it work like i want it to or is this a limitation of batch files?
set /p message=Unity:
set /p input=The variable:
set /p after=Unity:
:gen
setlocal
cd ..
cd rcs
echo doing background work, please wait a few seconds :)
for /f "delims=" %%a in (%input%.txt) do call set "$$%%random%%=%%a"
(for /f "tokens=1,* delims==" %%a in ('set $$') do echo(%%b)>new%input%.txt
endlocal
cls
set "File=C:\Users\%USERNAME%\Desktop\gg\rcs\new%input%.txt"
set /a count=0
echo background work done :)
timeout /t 1 >nul
SETLOCAL enabledelayedexpansion
for /F "tokens=* delims=" %%a in ('Type "%File%"') do (
Set /a count+=1
Set "output[!count!]=%%a"
)
For /L %%i in (1,1,%Count%) Do (
Call :Action "!output[%%i]!"
pause
)
Exit
::*******************************************************
:Action
cls
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo %message% %1 %after%
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo.
echo if you want to go back and change your inputs type back
echo if you want to continue generating, type gen
echo.
set /p instruction=
goto %instruction%
::*******************************************************
To get rid of the quotation marks, just use %~1 instead of %1.
I'm assuming, you want to input something like 'this $celeb is great' instead of the first three set /p lines (as your output is already in one line).
I used some fixed variables to keep it short - of course you would fetch them from the user and the text file instead, as you already did.
#echo off
setlocal EnableDelayedExpansion
set "count=3"
set "output[3]=John"
set "sentence=this $celeb is great."
REM above would be your 'set /p' instead
call :action "!output[%count%]!"
goto :of
:action
echo !sentence:$celeb=%~1!
(just to be clear: $celeb is not a variable - it's just a string, that we replace later, so from user's perspective, it behaves like a variable)

Batch For /R Results to be set menu choice

need a bit of help with a project.
Scenario :-
Manually migrating PC's to new Domain breaks a piece of software due to the new profile not having the settings from the old user profile - required to make it run. The old profile is called one thing, the new one - something else e.g.
C:\Users\Sue.Barnes.B3209 (old) C:\Users\Susan.Barnes.NGP (new)
Within the %localappdata% of each (old) profile there "maybe" a config file for this software, if the user has used it previously. E.g.
C:\Users\Sue.Barnes.B3209\AppData\Local\Acme_Limited\Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh\1.0.0.15\user.config
Objectives :-
I want to be able to scan through the C:\Users Folder and report back the full path, name & extension of file where it is found, then have the list set in a menu choice where upon input choice will copy the user.config file to the exact same location but in the currently logged on new profile appdata folder.
e.g.
Enumerating List Of User Profiles in the System...
Admin
Public
User
From the Profiles detecting active Configs...
C:\Users\Admin\AppData\Local\Acme_Limited\Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh\1.0.0.15\user.config
C:\Users\Public\AppData\Local\Acme_Limited\Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh\1.0.0.15\user.config
Press any key to continue . . .
However it is at this point I'm out of my depth. I cant seem to be able to create a choices menu of each instance where the file is found. However many are found, I'd like a number to be printed on the screen so I can choose the correct config to copy to the newly set up profile. Simply,
Xcopy /f C:\Users\Sue.Barnes.B3209\AppData\Local\Acme_Limited\Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh\1.0.0.15\user.config
%localappdata%\Acme_Limited\Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh\1.0.0.15\
Current code base :-
echo.
echo Enumerating List Of User Profiles in the System...
echo.
TIMEOUT /T 3 >NUL
dir /b C:\Users
echo.
echo From the Profiles detecting active Configs...
echo.
TIMEOUT /T 3 >NUL
for /R "C:\Users" %%a in (1.0.0.15\user.config*) do (
echo %%~dpnxa
)
)
echo.
pause
Any help be greatly appreciated, thanks
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
set "dontshow=u:\dontshow.txt"
set "configs=u:\configs.txt"
set "profiles=u:\profiles.txt"
:again
echo :>>"%dontshow%"
del "%configs%" >nul 2>nul
del "%profiles%" >nul 2>nul
:: Find all of the "user.config" files having ..\appdata\local\Acme_limited\...1.0.0.15
FOR /f "tokens=1-9delims=\" %%a IN (
'dir /s /b /a-d "%sourcedir%\user.config" '
) DO if /i "%%d"=="appdata" if /i "%%e"=="local" if /i "%%f"=="Acme_Limited" if /i "%%h"=="1.0.0.15" (
rem these are the users' config files that may be copied.
echo %%c|findstr /x /g:"%dontshow%" /i /L >nul
if errorlevel 1 >>"%configs%" echo %%c
)
:: Find all of the user profiles that are not in "dontshow" and do NOT have "user.config" - These are the profiles that may need to be processed
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%" '
) DO (
echo %%a|findstr /x /g:"%dontshow%" /i /L >nul
if errorlevel 1 echo %%a|findstr /x /g:"%configs%" /i /L >nul
if errorlevel 1 >>"%profiles%" echo %%a
)
:: Now we have a list of profiles with "user.config" missing in %profiles%
:: And possible source-profiles in %configs%
:: Show the list of "config missing" profiles
cls
findstr /n /v /L /c:":" "%profiles%"
:reselectd
set "selectiond="
set /p "selectiond=Choose destination profile "
if not defined selectiond goto :eof
for /f "tokens=1*delims=:" %%a in ('findstr /n /v /L /c:":" "%profiles%"') do if "%%a"=="%selectiond%" set "selectiond=%%b"&goto selects
echo Invalid selection
goto reselectd
:selects
for /L %%a in (1,1,4) do echo.
findstr /n /v /L /c:":" "%configs%"
:reselects
set "selections="
set /p "selections=Choose source profile "
if not defined selections goto :eof
for /f "tokens=1*delims=:" %%a in ('findstr /n /v /L /c:":" "%configs%"') do if "%%a"=="%selections%" set "selections=%%b"&goto process
echo Invalid selection
goto reselects
:process
echo Copy from profile "%selections%" to "%selectiond%" ?
choice
if errorlevel 2 goto again
:: Do the copy... just echoed, remove `echo` keyword to activate
ECHO md "%sourcedir%\%selectiond%\appdata\localAcme_Limited\whatever\1.0.0.15"
ECHO copy "%sourcedir%\%selections%\appdata\localAcme_Limited\whatever\1.0.0.15\user.config" "%sourcedir%\%selectiond%\appdata\localAcme_Limited\whatever\1.0.0.15"
choice /M "Add '%selections%' to processed file ? "
if errorlevel 2 goto processedd
>>"%dontshow%" echo %selections%
:processedd
choice /M "Add '%selectiond%' to processed file ? "
if errorlevel 2 goto again
>>"%dontshow%" echo %selectiond%
goto again
Interesting exercise. Lack of information about what Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh is about (constant string, change-per-user? What?), though - left as an exercise for OP to resolve.
You would need to change the setting of sourcedir to suit your circumstances. The listing uses a setting that suits my system.
I decided that the key part is the third directory level - the user-id. This approach uses files of user-id, two are temporary and one is permanent - "dontshow.txt" which contains a list of user-ids NOT to show. This can be manually maintained using an editor if required.
So - to start, add a line containing a single colon to the "dontshow" file. This is a dummy which can never match a real user-id and is required because findstr doesn't like an empty dictionary file.
The first step is to find all of the user.config files, and use for /f to process the filenames found, selecting the significant directory-levels. Having excluded any path that does not fit the criteria, the third level contents is matched against the exclusions in "dontshow.txt". If the name found is new, add it to the configs file.
Second verse - same as the first, but this time only looking at the directory names. Note that the entry is made to profiles if the name found is NOT on the dontshow list AND is also NOT on the config list.
Now select a destination profile by listing profiles and appending a prefix linenumber: using findstr. Enter a number (manual entry, unchecked) and then match the line number by using for/f.
Rinse and repeat for the configs file for the source profile.
Display the proposed command, accept a Y/N response then ask whether each name should be added to the dontshow list.
And straight on 'til morning.
Note that responding with Return to any of the set /p commands will exit the batch.

Literally echo the text "on"

I'm writing a windows CMD Batch file, that (for simplified purposes) is supposed to echo every line of this file:
Flash
your
lights
on
and
off
The problem is when it gets to the 4th and 6th words, it ends up running echo on and echo off, which does not actually echo the text, instead it just sets the state of echo to be ON and OFF.
for /F %%a in (DataFile.txt) do echo %%a
The resulting Output is:
Flash
your
lights
and
Is there a way to literally echo the text on and off?
According to this post on DosTips.com, the only safe way to echo any text is to use the odd-looking syntax echo(. So for your command line:
for /F %%a in (DataFile.txt) do echo(%%a
There is the syntax echo. commonly used, but this fails in case there is a file called echo. (no extension) in the current working directory.
The syntax echo/ sometimes used fails if you try to echo a string starting with a question mark (because / followed by ? is interpreted as the /? switch to display the help text for the command).
Try this:
#echo off
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ %userprofile%\Desktop\DataFile.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!"
echo(!var!
ENDLOCAL
)
Pause
Check out this link.
on and off, in the context of what you are doing won't work because they are what you call (reserved words in the language) They are used as #echo off or #echo on
The script I posted got around that minor problem. However my lack of of knowledge in batch forces me to conclude my answer as I have no idea of how the script does it.

How do I create a password that timeouts after certain period of time in batch file?

I want to make this code to ask for a password that timeouts after 10 seconds and if you wrote the correct password it goes to :wow but if it's incorrect it just continues the code . (the code is just an example)
#ECHO OFF
TIMEOUT /t 10>nul
exit
:wow
echo now this is fun!
pause
exit
MD5sum
Batch scripts, as they live in the world of plain text files, aren't very conducive to storing and matching passwords. After all, the person running the script could just as easily open it in Notepad and see the expected password. That's not very hacksy, now, is it?
These batch password questions pop up from time to time, and hard-coded passwords in scripts always irritate me. So how about, for a change, we obfuscate the password with an MD5 hash? There's no simple command built into Windows that makes this happen, but it can be accomplished with a (admittedly convoluted) PowerShell one-liner.
Save this helper script as md5sum.bat:
#echo off
setlocal
if "%~1"=="" goto :EOF
powershell "[Security.Cryptography.HashAlgorithm]::Create('MD5').ComputeHash([Text.Encoding]::UTF8.GetBytes('%~1')) | %%{write-host -n $_.tostring('x2')}"
Then use it to find the MD5 hash of the password you want like this:
md5sum.bat "password"
The result will output
5f4dcc3b5aa765d61d8327deb882cf99
Rather than hard coding the password itself into your script, you can now hard code 5f4dcc3b5aa765d61d8327deb882cf99.
User Entry
Now comes the interesting stuff. You can also borrow from Powershell to obfuscate the user entry like this:
#echo off
setlocal
<NUL set /P "=Password? "
set "psCommand=powershell -command "$p=read-host -AsSecureString;^
$m=[Runtime.InteropServices.Marshal];$m::PtrToStringAuto($m::SecureStringToBSTR($p))""
for /f "usebackq delims=" %%p in (`%psCommand%`) do set "pass=%%p"
setlocal enabledelayedexpansion
echo You entered !pass!
endlocal
Combine the two methods and you can check to see whether the password entered by the user matches the hash hard coded into the script.
#echo off
setlocal
<NUL set /P "=Password? "
set "psCommand=powershell "$p=read-host -AsSecureString;^
$m=[Runtime.InteropServices.Marshal];$x=$m::PtrToStringAuto($m::SecureStringToBSTR($p));^
[Security.Cryptography.HashAlgorithm]::Create('MD5').ComputeHash([Text.Encoding]::UTF8.GetBytes($x)) ^| %%{write-host -n $_.tostring('x2')}""
for /f "usebackq delims=" %%I in (`%psCommand%`) do (
if "%%~I"=="5f4dcc3b5aa765d61d8327deb882cf99" goto :match
)
echo Nope.
goto :EOF
:match
echo w00!
Voila! Now you can expect a user entry of password but the user can't easily see by opening in Notepad that password is the correct password. Cool, huh?
Self-Destruct
Back to your original question of how you can make this timeout after 10 seconds, you'll have to get a little creative. One solution would be to launch a helper script in the background that waits for 10 seconds, then kills all powershell.exe tasks. This can interfere with other powershell-ish stuff you might have running -- but let's be honest. Given the elementary nature of the question, I think it's safe to assume that won't be a problem in this situation.
I would do it this way:
#echo off
setlocal
if "%~1"=="helper" goto helper
start /b "" "%~f0" helper
<NUL set /P "=Password? "
set "psCommand=powershell "$p=read-host -AsSecureString;^
$m=[Runtime.InteropServices.Marshal];$x=$m::PtrToStringAuto($m::SecureStringToBSTR($p));^
[Security.Cryptography.HashAlgorithm]::Create('MD5').ComputeHash([Text.Encoding]::UTF8.GetBytes($x)) ^| %%{write-host -n $_.tostring('x2')}""
for /f "usebackq delims=" %%I in (`%psCommand%`) do (
waitfor /s %computername% /si PasswordEntered >NUL 2>NUL
if "%%~I"=="5f4dcc3b5aa765d61d8327deb882cf99" goto :match
)
echo Nope.
goto :EOF
:match
echo w00!
goto :EOF
:: // END MAIN RUNTIME
:helper
>NUL 2>NUL (
title Enter password.
waitfor PasswordEntered /t 10 || taskkill /im "powershell.exe" /f
)
exit
If you'd rather not taskkill Powershell, it is possible to make read-host time out, but I'll leave that as an exercise for the reader.
You could start a VBS file with a password prompt.
http://www.robvanderwoude.com/vbstech_ui_password.php
The link above links to a page with a password prompt script. You could add a timeout wich would wait for 10 seconds and then close.

How to delete text from a text file via batch

Have looked about the web but cant find anything that can help. I am trying to make a page that can delete something of a page. Have managed to make a search that can tell you if a word is on the .txt file. How would I put it into this?
cls
set /p SEARCH= Please enter what you want to look for?
for /f "Delims=" %%a in (test.txt) do (
set FIND=%%a
)
if %SEARCHS%==%FIND% goto FLIGHT HAS ARRIVED
echo We were not able to find %SEARCH%
pause
goto start
Does anybody know what I should do?
Thanks,
Alex
type file|find "string in lines to remove" /i /v >newfile
might help.
set /p reg=text:for /f "delims=" %%i in (file.txt) do if %%a'==%reg%' goto found
I can't tell what you want to do though so if this doesn't help please elaborate.
try this:
#ECHO OFF &SETLOCAL
set /p "SEARCH= Please enter what you want to look for? "
for /f "Delims=" %%a in ('find "%SEARCH%" test.txt') do set "FOUND=%%a"
if DEFINED FOUND goto FLIGHT_HAS_ARRIVED
echo We were not able to find %SEARCH%
pause
goto start
:FLIGHT_HAS_ARRIVED
ECHO %SEARCH% found: %FOUND%
goto:eof
You shouldn't use cmd command names for variable names (%FIND%).
Jump labels do not work as expected, if it contain spaces: FLIGHT HAS ARRIVED

Resources