findstr gets wrong line on commad - batch-file

i have a list with number of station and ip like this:
1 10.1.1.10
10 10.1.10.10
11 10.1.11.10
17 10.1.17.10
174 10.1.174.10
7602 10.16.2
7604 10.16.4
7605 10.16.5
the list is very big but this is the example.
i would like to use "findstr" to end number of station with "SET /P"
and get by that the IP.
this is what i've wrote:
#echo off
setlocal enabledelayedexpansion
set /p sn=
echo result is :
echo.
for /f "tokens=1-3" %%a in ('findstr /c:%sn% stations.list') do set station=%%a %%b %%c
echo %station%
echo.
pause
when i try to do some script it gets me for "1" it brings something else with the number "1" but no "1" exactly

Add the /b /e switches and 1 should get you the IP address on that line.
Your example doesn't use three tokens so I change it to 1,2 also:
#echo off
setlocal enabledelayedexpansion
set /p sn=
echo result is :
echo.
for /f "tokens=1,2" %%a in ('findstr /b /e /c:%sn% stations.list') do set station=%%a&set IP=%%b
echo %station%, %IP%
echo.
pause

Related

How to map numbers to a variable

I have the following script but I want to map the numbers to the variable but do not know how to. So if a user enters 0, I want it to search for the event name NewUser.
#echo off
mode con:cols=40 lines=40
set /p customerID="Enter Customer ID: "
CLS
:MENU
ECHO.
ECHO ...............................................
ECHO PLEASE SELECT THE EVENT FROM THE MENU BELOW
ECHO ...............................................
ECHO.
ECHO Event Code Event Name
ECHO.
ECHO 0 NewUser
ECHO 1 ExistingUser
ECHO 2 EmailAdded
ECHO 3 AccountProblem
ECHO 4 Lost
ECHO.
SET /P event=Type the event code and then press ENTER:
IF %event%==0 set event=NewUser GOTO find
IF %M%==1 set event=ExistingUser GOTO find
IF %M%==2 set event=EmailAdded GOTO find
IF %M%==3 set event=AccountProblem GOTO find
IF %M%==4 set event=Lost GOTO find
pause
:find
pause
setlocal enableextensions disabledelayedexpansion
pause
set "sourceFolder=C:\test"
set "targetFolder=C:\test2"
pause
set "customerID=%customerID%"
set "NewUser=%Event%"
pause
for /f "delims=" %%a in ('
findstr /m /s /l /c:"%customerID%" "%sourceFolder%\*"
^| findstr /f:/ /m /l /c:"%event%"
') do (
copy "%%~fa" "%targetFolder%"
)
pause
The first version of your code was closer to correct solution than current one; you need to use two nested for /F loops as follows:
for /f "delims=" %%a in ('
findstr /I /m /s /l /c:"%customerID%" "%sourceFolder%\*.txt"
') do for /f "delims=" %%A in ('
findstr /I /m /l /c:"%event%" "%%~fa"
') do (
rem 'copy' command is merely displayed using ECHO for debugging purposes
ECHO copy "%%~fa" "%targetFolder%"
)
Next commented code snippet could help to improve the script:
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "customerID="
:customerID
set /p customerID="Enter Customer ID: "
if not defined customerID goto :customerID
REM instead of above test, you could apply next statement about `set /P`:
REM If the user does not enter anything (just presses return)
REM then the variable will be unchanged and an ERRORLEVEL will be set.
rem CLS
:MENU
ECHO.
ECHO ...............................................
ECHO PLEASE SELECT THE EVENT FROM THE MENU BELOW
ECHO ...............................................
ECHO.
ECHO Event Code Event Name
ECHO.
ECHO 0 NewUser
ECHO 1 ExistingUser
ECHO 2 EmailAdded
ECHO 3 AccountProblem
ECHO 4 Lost
ECHO.
REM SET /P M=Type the event code and then press ENTER:
choice /C 01234 /M "Type the event code"
REM 0 means that an user's reply to "Terminate batch job (Y/N)?" was not "y"
IF %ERRORLEVEL% EQU 0 echo "Ctrl-C" or "Ctrl-Break" pressed&goto :NoSearch
REM 255 means another error
IF ERRORLEVEL 255 goto :MENU
REM ERRORLEVEL number Specifies a true condition if the last program run
REM returned an exit code EQUAL TO OR GREATER THAN the number
REM specified.
IF ERRORLEVEL 1 set "event=NewUser"
IF ERRORLEVEL 2 set "event=ExistingUser"
IF ERRORLEVEL 3 set "event=EmailAdded"
IF ERRORLEVEL 4 set "event=AccountProblem"
IF ERRORLEVEL 5 set "event=Lost"
REM Note that in above code, ERRORLEVEL parameters are tested in INCREASING order
REM Used only in this special case
REM (no need of GOTO statement, 'event' variable is set correctly)
REM
REM although CHOICE /? says:
REM When you use ERRORLEVEL parameters in a batch program,
REM list them in decreasing order.
:NOTE
set "sourceFolder=D:\test"
set "targetFolder=D:\test2"
rem ??? set "customerID=%customerID%"
rem ??? set "event=%event%"
rem debugging output
echo looking for "customerID=%customerID%" "event=%event%"
for /f "delims=" %%a in ('
findstr /I /m /s /l /c:"%customerID%" "%sourceFolder%\*.txt"
') do for /f "delims=" %%A in ('
findstr /I /m /l /c:"%event%" "%%~fa"
') do (
rem 'copy' command is merely displayed using ECHO for debugging purposes
ECHO copy "%%~fa" "%targetFolder%"
)
:NoSearch
pause
Change your For loop like this and retest:
FOR /F "DELIMS=" %%A IN (
'FINDSTR/MSC:"%customerID%" "%sourceFolder%\*"^|FINDSTR/MIF:/ /C:"%event%"'
) DO COPY "%%A" "%targetFolder%"
EDIT
I have added a modified version of your script to include the new requirement of a three digit event code. Just adjust it's value in the script as necessary, (lines nineteen to twenty three).
#ECHO OFF
MODE CON:COLS=52 LINES=40
SETLOCAL ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION
(SET sourceFolder=C:\test)
(SET targetFolder=C:\test2)
SET /P "customerID=Enter Customer ID: "
:MENU
CLS
ECHO=
ECHO= ..................................................
ECHO= PLEASE SELECT THE OPTION FROM THE EVENT MENU BELOW
ECHO= ..................................................
ECHO=
ECHO= Option Event Name Event Code
ECHO=
ECHO. 1. NewUser A00
ECHO. 2. ExistingUser A01
ECHO. 3. EmailAdded A02
ECHO. 4. AccountProblem A03
ECHO. 5. Lost A04
ECHO=
CHOICE /C 12345 /M "CHOOSE AN OPTION"
SET "Option=%ERRORLEVEL%"
FOR /F "TOKENS=1-4 DELIMS=. " %%A IN ('FINDSTR/BC:"ECHO. " "%~f0"'
) DO IF "%%B"=="%Option%" (SET "Name=%%C" & SET "Code=%%D")
FOR /F "DELIMS=" %%A IN (
'FINDSTR/MISC:"%customerID%" "%sourceFolder%\*"^|FINDSTR/MIF:/ /C:"%Name%"'
) DO COPY "%%A" "%targetFolder%"
PAUSE
Please make sure that %sourceFolder% is a full path and %targetFolder% already exists, (see line six).

Splitting ip and port in ip:port format using batch

For the program I am currently working on I am taking a value, which is a proxy in ip:port format, I need to be able to split the ip and port to different variables so that a different program that needs ip and port separate will be able to work. The program is basically an automated ip/proxy switcher for minecraft, just for in game reasons, I have all the code working except for the part that actually changed the proxy. I am not getting any error message, only that I don't actually know what code to write. Anyways, here is my code.
#echo off
color b
title minecraft proxy switcher
set nLine=0
echo input full path to text file containing proxies
set /P "filepath=>"
echo end >> %filepath%
:top
cls
set /A nLine=%nLine%+1
echo now at proxy number %nLine%
CALL :ReadNthLine "%filepath%" %nLine%
PAUSE >NUL & goto:top
GOTO :EOF
::***************************************************************************************
:ReadNthLine File nLine
FOR /F %%A IN ('^<"%~1" FIND /C /V ""') DO IF %2 GTR %%A (ECHO Error: No such line %2. 1>&2 & EXIT /b 1)
FOR /F "tokens=1* delims=]" %%A IN ('^<"%~1" FIND /N /V "" ^| FINDSTR /B /C:"[%2]"') DO set http_proxy=%%B
goto finish
::***************************************************************************************
:finish
if %http_proxy%==end (
cls
echo all proxies have been used
echo will return to top of list in 5 seconds
TIMEOUT /T 5 /NOBREAK
set nLine=0
goto top
)
java -DsocksProxyHost=ip -DsocksProxyPort=port -Xmx800m -jar MinecraftLauncher.exe
echo New ip is %http_proxy%
echo waiting for user input
echo press any key for a new ip
pause
goto top
Any help is greatly appreciated, also if you notice something else that's badly written or incorrect in my code please tell me.
split the string with a for, using proper tokens and delimiters:
set "line=192.168.1.1:8080"
for /f "tokens=1,2 delims=:" %%a in ("%line%") do (
set server=%%a
set port=%%b
)
echo Server %server% Port %port%
here is a basic code skeleton which processes the file line after line (your way works, but this is way easier):
#echo off
set /p "filepath=File: "
:top
set n=0
for /f "tokens=1,2 delims=:" %%a in (%filepath%) do call :process %%a %%b
timeout 5
goto :top
:process
echo trying %n%
set /a n+=1
echo host: %1
echo port: %2
pause
goto :eof

Use of relational operators when reading a file from CMD

I am trying to create a command line program which outputs numbers from a file only greater than (larger than) specified one.
Say like there's a file output.txt with lots of numbers (one per line) and I need to get the only ones less than 5000.
Here's a part of my code, but it doesn't work as expected:
CHOICE /C 12
SET /P Comparative_number="Input a number: "
IF %ErrorLevel%==2 GOTO LESS_OPERATION
FOR /F %%A IN (%OutputFile%) DO IF %%A GTR %Comparative_number% ECHO %%A
ECHO. & ECHO End of output & EXIT /B
:LESS_OPERATION
FOR /F %%A IN (%OutputFile%) DO IF %%A LSS %Comparative_number% ECHO %%A
ECHO. & ECHO End of output & EXIT /B
What I am doing wrong?
The command extensions are enabled by default. But if a batch script depends on command extensions as when using GTR and LSS in an IF condition is always advisable to enable them explicitly.
The integer numbers must be listed in the file referenced via environment variable OutputFile line by line, for example:
50
23
478
-3425
9071
A batch code which worked:
#ECHO OFF
SETLOCAL EnableExtensions
SET "OutputFile=C:\Temp\File With Numbers Listed Line By Line.txt"
ECHO.
ECHO Please choose the comparison:
ECHO.
ECHO 1 ... Greater Than
ECHO 2 ... Smaller Than
ECHO.
CHOICE /C:12 /N /M "Your choice: "
ECHO.
SET "Comparative_number=0"
SET /P "Comparative_number=Input a number: "
ECHO.
IF %ErrorLevel%==2 GOTO LESS_OPERATION
FOR /F "usebackq" %%A IN ("%OutputFile%") DO IF %%A GTR %Comparative_number% ECHO %%A
ECHO.
ECHO End of output
ENDLOCAL
EXIT /B
:LESS_OPERATION
FOR /F "usebackq" %%A IN ("%OutputFile%") DO IF %%A LSS %Comparative_number% ECHO %%A
ECHO.
ECHO End of output
ENDLOCAL
EXIT /B
Why your code does not work in comparison to this slightly modified code depends most likely on name of output file, how the numbers are listed in output file and how you have used command CHOICE.

Typing text with not yet (but will be) defined variables in batch

So i want to create typing text for a Turn Based RPG (in batch), where you have a person controlling almost everything that interacts with the players.
I want it so when everyone's turn is over, it will display what everyone did, but in a dramatic way.
Now some of us know
for %%i in (h e l l o) do (set /p a=%%i<nul & ping 0.0.0.0 -n 2.5>nul 2>&1)
but I want to have a variable do this using
set /p Write=<Write.txt
so i can have something like for %%i in (%write%) do (set /p a=%%i<nul & ping 0.0.0.0 -n 2.5>nul 2>&1)
to make it write one letter at a time.
Thanks!
The Batch file below use an interesting trick I borrowed from this post that convert the Ascii (1-byte) characters into Unicode 2-bytes characters via /U switch of cmd.exe (inserting a zero-byte between characters), and then split the zero-bytes in individual lines via find command:
#echo off
setlocal
echo Hello, World!> Write.txt
for /F %%a in ('echo prompt $H^| cmd') do set "BS=%%a"
for /F "delims=" %%i in ('cmd /D /U /C type Write.txt ^| find /V ""') do (
set /P "=X%BS%%%i" < NUL
ping localhost -n 2 > NUL
)
EDIT: New version added
I modified previous code to show several lines in the right way; it also use JScript's sleep method in order to use variable delay intervals between each character, this point results in an output appearing in a more dramatic way.
#if (#CodeSection == #Batch) #then
#echo off
(
echo Hello, World!
echo The World is ending!
) > Write.txt
for /F %%a in ('echo prompt $H^| cmd') do set "BS=%%a"
for /F "delims=" %%a in (Write.txt) do (
for /F "delims=" %%i in ('cmd /D /U /C set /P "=%%a"^<NUL ^| find /V ""') do (
set /P "=X%BS%%%i" < NUL
REM ping localhost -n 3 > NUL
cscript //nologo //E:JScript "%~F0"
)
echo/
)
goto :EOF
#end
// JScript section: wait a random number of milliseconds between 0 and 300
WScript.Sleep(300*Math.random());
This is a version of Ghost typer that uses a variable, to display text on a screen in a way that a person might type it.
#echo off
:: Ghost typer - variable version
:: shows text in a variable on the screen in a way that a person might type it.
:: Do not use " in the text to be printed, replace them with '
:: Adjust speed variable - higher numbers increase typing speed - default=3
set speed=6
:: backspace variable is used in the printing routine
for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
set "line=Your dog was eaten by a red winged dragon!"
call :begin
set "line=Two sloths ate all your chocolate!"
call :begin
set "line=A genie appears, and grants you 4 wishes...."
call :begin
set "line=How many woodchucks does it take?"
call :begin
pause>nul
goto :EOF
:begin
set num=0
:type
call set "letter=%%line:~%num%,1%%"
set "delay=%random%%random%%random%%random%%random%%random%%random%"
set "delay=%delay:~-6%"
if not "%letter%"=="" set /p "=a%bs%%letter%" <nul
for /L %%b in (1,%speed%,%delay%) do rem
if "%letter%"=="" echo.&goto :EOF
set /a num+=1
goto :type
To print the characters one by one of an arbitrary string, you could use the following:
#echo off
rem define string to print:
set "WRITE=Hello world!"
setlocal EnableDelayedExpansion
for /L %%I in (0,1,8191) do (
set "CHAR=!WRITE:~%%I,1!"
rem if "!WRITE:~%%I,2!"=="!CHAR! " set "CHAR=!CHAR! "
if "!CHAR!"=="" goto :SKIP
< nul set /P "DUMMY=!CHAR!"
> nul 2>&1 ping 127.0.0.1 -n 2
)
:SKIP
endlocal
As you will notice, the SPACE within the string in WRITE is not printed, because set /P does not print any (leading) spaces in the prompt string. To work around this, remove the rem in front of the if inside of the for loop. Actually this previews the next character and appends it to the current one in case it is a space, as set /P prints trailing spaces.
#echo off
setlocal enabledelayedexpansion
for /f %%A in ('"prompt $H &echo on &for %%B in (1) do rem"') do set BS=%%A
set /P string=<write.txt
call :StrLen "%string%" _len1
for /L %%A in (0,1,%_len1%) do (
set "substring=!string:~%%A,1!"
set /p "=.%BS%!substring!" <nul
> nul 2>&1 ping 127.0.0.1 -n 1
)
echo.
pause
GOTO :EOF
REM Subroutine to return the length of a string variable
:StrLen [string] [len-var]
set "_str=A%~1" & set "_len=0"
for /L %%A in (12,-1,0) do (set /a "_len|=1<<%%A" & for %%B in (!_len!) do if "!_str:~%%B,1!"=="" set /a "_len&=~1<<%%A")
set /a %~2=%_len%
exit /b

Batch script that makes a numbered menu to view log files

I have recently started to learn how to make batch files. I have a folder that contains bunch of internet related log files. When I run the .cmd file (located in the same folder) I want it to be able to find out how many log files are in the folder and make a numbered menu from it. So lets say there are twenty files in the folder, then the user must be able to select from 1 to 21. 21 will close the batch file. Here is what I have done so far:
#echo off
setlocal enableextensions enabledelayedexpansion
set RawData1=TempData%random%.tmp
set FileCtr=0
:MAIN
dir *.log /b | findstr /i /n ".log" > %RawData1%
for /f "tokens=1 delims=:" %%a in (%RawData1%) do set FileCtr=%%a
set /a ExitCode=%FileCtr% + 1
set UserChoice=%ExitCode%
echo.
echo +++++++++++++++++++++++++++
echo Weblog File Viewer
echo +++++++++++++++++++++++++++
for /f "tokens=1-2 delims=:." %%a in (%RawData1%) do echo %%a. %%b
echo %Exitcode%. To Quit.
set /p UserChoice= Choose item number from menu (%UserChoice%):
echo\
echo user entered: %UserChoice%
pause
:THEEND
del /q %RawData1%
So what this batch file can do for now is that it figures out the number of log files and makes a numbered menu from it. Of course it won't show the filetype which is how I wanted it. So "Kelley-Blue-Book.log" for example is shown only as "Kelley-Blue-Book". However, if the user selects say number 4 from the list the program will terminate because I couldn't figure out how to make it actually open the desired log file using notepad.
This should do what you want:
#echo Off
setlocal EnableDelayedExpansion
set "Count=0"
pushd "%~dp0"
echo.
echo +++++++++++++++++++++++++++
echo Weblog File Viewer
echo +++++++++++++++++++++++++++
for %%A in (*.log) do (
set /a "Count+=1"
set "Menu[!Count!]=%%~fA"
set "Number= !Count!"
echo !Number:~-3!. %%~nA
)
set /a "Count+=1"
set "Number= %Count%"
echo %Number:~-3%. To Quit.
:Prompt
set "UserChoice="
set /p "UserChoice= Choose item number from menu (%Count%):"
if not defined UserChoice goto Prompt
set "UserChoice=%UserChoice:"=%"
if "%UserChoice%"=="%Count%" goto Done
for /f "tokens=1,* delims==" %%A in ('set Menu') do (
if /i "Menu[%UserChoice%]"=="%%~A" (
notepad "%%~fB"
set "UserChoice="
)
)
if defined UserChoice echo Invalid Choice.
goto Prompt
:Done
popd
endlocal
exit /b 0
Let me know if you want any explanations.
#echo off
setlocal enableextensions
set RawData1=TempData%random%.tmp
rem Get numbered list of files
dir /b "*.log" | findstr /i /n ".log" > %RawData1%
rem We could use 0 as exitCode,
rem but to keep original behaviour
rem lets count the number of files
for /F "tokens=*" %%f in ('type %RawData1% ^| find /c /v "" ') do set /A ExitCode=%%f + 1
if %ExitCode%==0 (
echo No log files
goto endProcess
)
rem show menu
for /f "tokens=1-2 delims=:." %%a in (%RawData1%) do echo %%a. %%b
echo %Exitcode%. To Quit.
set UserChoice=%ExitCode%
set /p UserChoice= Choose item number from menu (%UserChoice%):
if "%UserChoice%"=="" goto :EOF
if "%UserChoice%"=="%ExitCode%" goto endProcess
rem Search indicated file in list
set SelectedFile=
for /f "tokens=2 delims=:" %%f in ('findstr /B "%UserChoice%:" %RawData1%') do set SelectedFile=%%f
if "%SelectedFile%"=="" (
echo Incorrect selection
goto endProcess
)
if not exist %SelectedFile% (
echo File deleted
goto endProcess
)
notepad %SelectedFile%
:endProcess
del /q %RawData1%

Resources