cmd script for ping to find average, loss and IP - windows

I look through stackoverflow, found several similar topics bot no one from them wasn't about cmd
The question is:
I have a website, for example route4me.com and I need to ping it and save into file only: IP, %loss and average time
Can anybody explain how to use tockens and delims since I'm total noob.
Found an article, that explains how to:
Let's have a closer look at the output of the PING command:
we want the (unknown) second word from the first line (actually, the
second line, because the first line is blank) that first line contains
the (known) IP address enclosed in square brackets [10.100.0.14] none
of the other lines contain the IP address enclosed in square brackets,
nor any other string in square brackets First let's mark (yellow
highlights) the boundaries of the requested word REMOTE_PC:
Pinging REMOTE_PC [10.100.0.14] with 32 bytes of data:
Reply from 10.100.0.14: bytes=32 time<10ms TTL=128
Ping statistics for 10.100.0.14: Packets: Sent = 4, Received = 4,
Lost = 0 (0% loss), Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms This makes our choice
for the delimiters, delims, quite obvious: a space. If we mark (yellow
highlights) all spaces, we can easily see which tokens are available:
Pinging REMOTE_PC [10.100.0.14] with 32 bytes of data:
token=1 token=2 token=3 4 5 6 7 8 In this case,
we're only interested in tokens 2 and 3:
token 2 is the requested computer name token 3 can be used to check if
we're dealing with the correct line: it should equal our original IP
address enclosed in square brackets So we're only interested in the
tokens 2 and 3:
Pinging REMOTE_PC [10.100.0.14] with 32 bytes of data:
token=2 token=3 This leads us to the following command line:
FOR /F "tokens=2,3 delims= " %%A IN ('PING -a %1') DO IF "%%B"=="[%1]"
SET PC=%%A %1 is the value of the first command line argument passed
to our batch file. In our case, the IP address to be investigated.
IF "%%B"=="[%1]" checks if the third word (token=3) equals the
original IP address (%1) enclosed in square brackets ([%1]). If we
were to skip this test, the end result for token 2 would be the equal
sign (=) from the last line (just try it). If the test matches, the
second word (token=2) is stored in a variable named PC.
Note that the first token specified (token 2) is stored in the
variable specified (%%A), and the following token specified (token 3)
in the following variable (in this case: %%B).
Our batch file thus far:
#ECHO OFF FOR /F "tokens=2,3 delims= " %%A IN ('PING -a %1') DO IF
"%%B"=="[%1]" SET PC=%%A SET PC The last line, SET PC, displays the
actual value of the variable PC. I added it for debugging purposes.
(Actually, SET PC will display all variables whose names begin with
"PC".)
But for me this is all totally new.

Let's break this down.
Basically, tokens are parts of a string and delims(delimiter) are the text to separate the tokens. Consider this example:
set str=This.String.Is.Separated.By.Fullstops
for /f "tokens=1,2 delims=." %%a in ("%str%") do echo %%a %%b
The for loops will separate the text by ., and now the text are formatted like so:
Tokens: 1 2 3 4 5 6
Text : This String Is Separated By Fullstops
and we only need the first two tokens, which is This and String. echo %%a will return This, and echo %%b will return the String. But echo %%c will not return Is, as the for loop only process the first two tokens as stated in "tokens=1,2.
Back to the for loop.
FOR /F "tokens=2,3 delims= " %%A IN ('PING -a %1') DO IF "%%B"=="[%1]" SET PC=%%A
This time, the for loops only get the result of the command PING -a %1. The result will be:
Tokens: 1 2 3 4 5 6 7 8
Text : Pinging REMOTE_PC [10.100.0.14] with 32 bytes of data:
and we only take the 2nd token. Remember, even though token 2 does not seems to be %%A, but since in the tokens settings, we've set the first outputted variable to be the text with the 2nd token.
The IF statement checks if the 2nd outputted variable with token 3, which is:
[10.100.0.14]
and this equal to the first command-line argument. If so, it set PC to the variable with token 1, which is REMOTE_PC, your PC name.
To get the information you need, we would introduce another setting called skip.Skip defines how many lines to skip, and read the line after it.
for /f "tokens=11 skip=8 delims= " %%a in ('ping -a google.com') do echo %%a
This should get you the loss percentage(maybe not because I don't use the Russian language on my PC.) Feel free to adjust it and make it work for you.

#echo off
setlocal
call :get route4me.com
call :get microsoft.com
call :get google.com
goto :eof
:get
REM set a default value for 'avrg':
set "avrg= ---"
REM do the ping one time...:
>temp ping %1
REM ... and process the output several times to collect the data:
for /f "tokens=2 delims=[]" %%a in (temp) do set "ip=%%a"
for /f "tokens=1 delims=( " %%a in ('find "(" temp') do set "loss=%%a"
for /f "tokens=4 delims==" %%a in ('find "ms, " temp') do set "avrg=%%a"
echo %1,%ip%,%loss%,%avrg:~1%
The first for loop gets the IP.
There will be only one line containing [ and ], so we can safely process the whole line without another line overwriting our result (no other line will have a token2).
The second for loop gets the loss percentage.
It's the only line containing ( and ), but this time, we have to use token 1. so the next line would destroy our token. So we use find to filter only this line (every line will have a first token).
The third for loop gets the average value.
Again, we need a filter the line (I'm using ms,, hoping it's international; the other two should work in every language)
If there is no such line, the tokens keeps empty, so the set will not execute and the default value is kept.
(trying to keep it language independend is also the reason for the delimiter = only in the last forloop and removing the space afterwards with %avrg:~1%)
Working with a temporary file doesn't only make it faster (one ping instead of three), but also ensures, the data is consistent (get all values from the same ping command).
I prefer filtering over skipping, because you can never be sure, if the lines to skip are the same in every case (responsive address vs. unresponsive address)

Related

Echoing output of command from variable

I'm trying to create a simple batch script that stores the output of a command to tmp file, stores the content of the tmp file to a variable, and outputs the variable:
#setlocal enableextensions enabledelayedexpansion
#echo off
ping -n 1 10.1.0.2 > tmp
SET #var= < tmp
ECHO %#var%
del tmp
I would expect the above to work, but it outpus:
C:\Documents and Settings\Administrator\Desktop>pinger.bat
ECHO is off.
(Nb: taking the #echo off just outputs ECHO is on, including echoing all the lines of code)
The question pointed by #rostok (my answer here), shows the reason to not use the received packets to determine if the host is or not online. On the same subnet, over ipv4, with an offline host, you will get a "unreachable" error, but the packets are received.
For a simple test in ipv4, the linked answer can handle your problem. For a more robust test over ipv4 or ipv6 (that show different behaviour), this could help.
Anyway, the code to get the required data directly from the ping command,
set "received="
for /f "skip=6 tokens=5 delims==, " %%a in ('ping -n 1 10.1.0.2') do (
if not defined received set "received=%%a"
)
or from the file
set "received="
for /f "usebackq skip=6 tokens=5 delims==, " %%a in ("tmpFile") do (
if not defined received set "received=%%a"
)
Where the skip clause indicates that the first six lines should be skipped, and the tokens and delims select the required element inside the line
Packets: Send = 1, Received = 1,
^ ^^^ ^^ ^^^ ^ Delimiter position
1 2 3 4 5 Token number
But as said, this is not a reliable way to solve the problem

How do I check whether or not a variable is set in a FOR loop?

I have this FOR loop:
for /F "tokens=1,2,3,4,5 delims=():/ " %%a in (svn.txt) DO (
While it explicitly calls for 5 tokens there may be only 3 or 4.
Is there a better way to code "tokens" to get the number of tokens in the line being parsed"
How do I tell if the third (for example) token has a value assigned to it? I've tried IF NOT DEFINED but with tokens=1,2,3,4,5 apparently %%c, %%d and %%e are always defined even if their value is %%c, %%d and %%e. I can't figure out how to check whether these variables have their own name assigned or a real value.
for /f "tokens=1-5 delims=():/ " %%a in (svn.txt) do (
if "%%c"=="" echo third token does not contain data
)
Since you are requesting 5 tokens, they will be defined for all the iterations of the loop. They will hold a value or not depending of the tokenization of the line.
If none of the tokens get data when reading/parsing the line, the code in the do clause will not be executed for this line.
Duh. if [%%e] EQU []. I had this at one point but had other logic issues I was blaming on this.

CMD return specific lines from piped input

Bored in class trying to figure this out.
On windows command prompt:
ipconfig /all return all the loopback, tunnel, etc.
if I run ipconfig /all | find /n "Internal" it will return [11]Ethernet Adapter Internal. What I want to do is substring the 11 off the beginning and then pipe this to something else which will allow me to return lines 11-19 or whatever. Can you do this in a single line similar to jquery and chaining?
It is simple to parse out the 11 using a FOR /F loop. But making use of that value is difficult in a one liner from the command line.
Here is the best I could come up with for a one liner to run from the command line.
set "stop="&for /f "delims=[]" %N in ('ipconfig /all^|find /n "Internal"') do #for /f "tokens=1* delims=:" %A in ('ipconfig /all^|findstr /n "^"') do #if %A geq %N if not defined stop echo(%B&>nul 2>nul set /a 1/(%A-%N-8)||set stop=1
The shortest one liner I could think of uses a different strategy.
set n=&for /f "delims=" %A in ('ipconfig/all') do #if defined n (set/a"1/n,n-=1">nul 2>&1&&echo %A) else echo %A|find "Internal"&&set n=8
But the above solution ignores blank lines.
If you want to preserve blank lines then the following works:
set n=&for /f "tokens=1* delims=:" %A in ('ipconfig/all^|findstr/n "^"') do #if defined n (set/a"1/n,n-=1">nul 2>&1&&echo(%B) else echo %B|find "Internal"&&set n=8
EDIT
I shortened and simplified the logic of the 2nd and 3rd solutions a bit.
I'll try to explain the 2nd option:
I first explicitly undefine a counter and then use FOR to read the output of the IPCONFIG/ALL commmand. Now begins the fun part within the DO clause.
At first the counter is undefined so the ELSE clause is executed. I pipe the current line to FIND looking for "Internal". If the string is not found then nothing happens and we progress to the next line. But if it is found then the line is printed. Then the code after && is executed since the string was found. There I set the counter to 8 because we want the next 8 lines printed.
The counter is defined for the remainder of the lines, so we now switch to the first part of the IF statement. I use SET /A to do some math. First I divide 1 by the current value of the counter. IF the counter is 0 then an error is raised and the rest of the statement is ignored. If the counter is not 0 then I next decrement the counter by 1. I redirect both stdout and stderr to nul because we don't want to see any messages from the SET /A command. If the SET command was successful, then I echo the line. Since I initially set the counter to 8 when the string was found, up to 8 lines will be printed before the counter reaches 0.

DOS - Trying to understand delimiters to find lowest line count inf files

I found a bug in a bat file I was writing and by accident found a fix however I don't understand why the fix worked.. Which is ultimately my question, or if there are other problems with this logic that I have not discovered.
The script does a line count in 2 or more files then the goal is to find the file with the lowest line count and later use that count in a variable later in the script as a parameter.
Example file 1 (9 lines):
Wrote,0
Wrote,1
Wrote,2
Wrote,3
Wrote,4
Wrote,5
Wrote,6
Wrote,7
Wrote,8
Example file 2 (10 lines):
Wrote,0
Wrote,1
Wrote,2
Wrote,3
Wrote,4
Wrote,5
Wrote,6
Wrote,7
Wrote,8
Wrote,9
The main difference that I see is that lines 9 & 10 in file 2 are two digit line numbers
NOTE: I am not referring to the actual value on each line but only the line number's count value as my code does not try to parse the lines but only get the line count.
Near the top of the code I create then append the count values for each file into a temp file called ~numbers.txt so to simulate that process here assume my starting code is:
echo 9 > ~numbers.txt
echo 10 >> ~numbers.txt
type ~numbers.txt
So now I have a file with two lines "9" and "10" and of course 9 is lower than 10 but it also is one digit less than 10.
Now I attempt to find the lowest number contained in the file ~numbers.txt by reading the 1st line into a variable then looping and evaluating if current value is less than prior value.
setlocal enabledelayedexpansion
set /p lowest=<~numbers.txt
FOR /F "delims=" %%G in (~numbers.txt) DO IF %%G LSS !lowest! SET lowest=%%G
echo lowest num = %lowest%
When I run this code I get this output which is wrong:
lowest num = 10
What I have found is that if I remove the "delims=" from the FOR loop I will get the correct result of 9.
ALSO and what really screws up my understanding of the problem; If I only change the values in ~numbers.txt to 10 and 100 and leave the FOR loop line alone (keeping "delims=" ) then I get the correct value of 10 as my answer???
This is bad because it implies that my logic is flawed and that other number combinations will also yield different results.
Can anyone explain to me why this is the case and/or give an example on how to get the correct lowest number regardless of the values?
Thanks...
If you don't see something it doesn't mean it doesn't exist. (I'm talking of spaces here)
Try this instead:
> ~numbers.txt echo 9<press ENTER immediately>
>> ~numbers.txt echo 10<press ENTER immediately>
This will be truly WYSIWYG, no spaces at the end of line, no text comparisons by if because strings are not all numbers.
Of course, stripping the spaces with default delims (one of which is a space) also works fine as you have noticed already.
Consider this way of determining lowest line count:
set /a minlines=0x7FFFFFFF
for /f "tokens=2 delims=:" %%a in ('find /c /v "" *.txt') do set /a minlines="%%a-(minlines-%%a)*(minlines-%%a>>255)"
echo %minlines%
Note: no ifs, no delayed expansion

Defining these batch commands

Over the past few years I've really found Stackoverflow to be very helpful, and decided to create an account - this is my first post.
Example situation - I have a fair few of these images, of different subjects -
AAA_BBB_randomDigits_front.jpg
AAA_BBB_randomDigits_left.jpg
AAA_BBB_randomDigits_right.jpg
ZZZ_EEE_randomDigits_front.jpg
ZZZ_EEE_randomDigits_left.jpg
ZZZ_EEE_randomDigits_right.jpg
I would like them to all be grouped up in folders as -
AAA_BBB_randomDigits\(contains left, front and right)
ZZZ_EEE_randomDigits\(contains left, front and right)
The code I currently have works -
#echo off
for /f "tokens=1-3 delims=_" %%a in ('dir /b /a-d *_*_*_*.*') do (
md "%%a_%%b_%%c" 2>nul
move "%%a_%%b_%%c*" "%%a_%%b_%%c"
)
pause
However, I would love it if someone could explain to me -
What's %%a?
What's dir /b /a-d and why do I need it?
Is it neccessary to have #echo off and pause?
Thanks guys, I really appreciate it.
For documentation, see commandname /? from the prompt.
dir /b /a-d filemask performs a directory listing /b specifies filenames only - no size, date, header or footer. The /a-d excludes directorynames.
You need it to provide the names to the for /f command.
for /f reads the "filename" in parentheses (it can be a real filename or a single-quoted command (like dir) or a double-quoted literal string) and assigns values to the metavariable (in this case, %%a) according to the specified options (the part in quotes directly following the /f).
The delims option specifies which set of characters is used for parsing the line of data arriving from the "file" specified. The line is then interpreted as a series of tokens, separated by delimiter-sequences. By default, delims is Space and Tab. It's common to turn delims off entirely using "...delims=" in which case, there is but one token (the entire line). Note that any characters between delims= and " are equally-ranking and case-sensitive - it is a set of delimiters which replaces Space and Tab, not a delimiter-string.
The tokens option specifies which tokens are selected, by number, starting at 1. The special token * means "the remainder of the line following the highest-number token specified (including any delimiter characters)". By default, tokens=1.
%%a is a metavariable. It is the variable that holds the first token number selected from the tokens= list. Each selected token number is assigned to the next metavariable name in alphabetical sequence, hence in your example, since you have tokens=1-3 then %%a is the first token, %%b the second and %%c the third. Metavariables are always one letter (some other characters are sometimes used - but numerics are definitely not allowed) and the name is case-sensitive (normally, batch is case-insensitive). %%a, %%A and %a% are all different variables. %a% and %A% are the same variable.
A metavariable is only valid within the for loop where it was created. When the for loop ends, the variable disappears.
#echo off simply turns off the command-echoing that batch would otherwise produce (show the command on the console, then execute it). It's used to reduce clutter on the display. When debugging a section of code, it's normal to set echo to on (echo on) and then off again (echo off) to show precisely what instructions are being executed. The # means "don't report this command to the console"
The pause simply waits until a response is received from the keyboard. It's used to allow the display to be read rather than simply continuing directly to the next instruction. It's often used in debugging and also to allow the result of a batch to be held for the user if the batch is executed by using point-click-and-giggle.

Resources