batch counting findstr results for /f - batch-file

I have an apache.log file. Im trying to make a batch file to be able to count the total amount of logins. Basically a number of lines.
My initial idea was to set a variable results=0 and whenever findstr command gets a result i get +1 to variable value and in the end display the value. Dont know if thats the correct way of thinking.
so far i've got the impression for /f command will probably be the key, though i've never used it so many parts are unclear to me.
here is the example of .log file line
67.195.112.96 - - [22/Feb/2010:00:06:03 +0200] "GET /www/kurpiai/dalyviai/?did=118 HTTP/1.0" 200 41119 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)"
my attempt so far goes as follows:
findstr ^[1-9] apache.log
for /f %%G in ('findstr ^[1-9] apache.log') do echo result %%G
now i understand that in this case %%G value gets replaced with each findstr result. and with this i get echo of every line that matches findstr and after that every ip adress. why?
i believe maybe somehow i could use the fact that %%G value changes every time to set my own variable. why does %%G get an ip value exactly?
or maybe im wrong and i dont need for /f for this task at all?

I'd say you don't. Just combine your findstr command with the DOS style wc -l:
findstr "^[1-9]" abc.txt | find /v "" /c
The first part selects the lines which match your intentions, and the second part counts (/c) those lines not matching nothing (i.e., all).
edit:
If you need the result in a variable:
for /f %%a in ('findstr /R "^[1-9]" abc.txt ^| find /c /v ""') do set "count=%%a"

Related

How to Find line in text file and export line number

I am building a Username and Password function for a batch file, and I have the system to read from 2 text files, Uname and Pass, and find the usernames and passwords, but the system is pulling any password listed in Pass. How can I read the line the username is on, set the password to only accept the corresponding line in the Pass text file?
FOR /F "tokens=* delims=" %%x in (Users.txt) DO IF '%uname%'=='%%x' goto AdmCont
rem FOR /F "tokens=* delims=" %%x in (Pass.txt) DO IF '%code%'=='%%x' goto AdmCont
Here is a simpler solution:
for /f "delims=: tokens=1,2" %A IN ('findstr /n "%uname%" Users.txt') do ( #set "number_of_line=%A" && #set "_uname=%B" )
Or, using find instead of findstr (quite complicated):
for /f "eol=- delims=[] tokens=1-2" %A IN ('find /n "%uname%" Users.txt') do ( #set "number_of_line=%A" && #set "_uname=%B" )
As in your post you have requested batch file code (you have double percent signs (%%)) you can double the percent-signs of the variables.
Let me explain my code:
In both two loops, we parse output of commands. You should know the command-output-format and why using findstr is much simpler.
findstr
We use /n option with findstr which tells it to echo the line that found string specified.
After /n option, we specify string that should be searched in specified after file.
After that, we specify the file we want to search the specified string.
The output will be:
%line_number%:%content_of_line%
So, we parse it saying:
DON'T PARSE : symbol into token with delims=: option!
Access the line_number with %(%)A and content_of_line with %(%)B using tokens=1,2 option.
Well known: specify variable letter add IN, then command to be parsed and set to variables number of line and its content.
find
We use /n option with find which tells it to echo the line that found string specified.
After /n option, we specify string that should be searched in specified after file.
After that, we specify the file we want to search the specified string.
The syntax is quite similar, but the output is completely different!:
---------- %FILENAME_SPECIFIED_WITH_CAPITAL_LETTERS%
[%line_number%]%line_content%
So, here:
We ignore lines starting with - with eol=- option.
We don't parse [] symbols into tokens with delims=[].
We want to access line_number with %(%)A and line_content with %(%)B, so, we add tokens=1,2 option.
Then, continuing as above (well known).
For better understanding how these commands work, I suggest you to open a new cmd window and type:
for /?
find /?
findstr /?
Try some examples of yours with find and finstr to completely understand how they work.
Some interesting references for further reading:
https://ss64.com/nt/findstr.html
https://ss64.com/nt/for_cmd.html
https://ss64.com/nt/find.html

WMIC call in BATCH FOR command Returns unexplained Error

I am trying to create a Volume Shadow copy from a BATCH file but have encountered a issue I am unable to explain.
When running the below command:
FOR /F "tokens=3" %%A IN ('"WMIC shadowcopy call create ClientAccessible,"C:\""^| FIND /I "ShadowID"') DO SET ID=%%A
I receive the below error
Invalid format. Hint <paramlist> = <param> [, <paramlist>].
but if I replace FIND with FINDSTR and remove the quotes from around the word I am searching for it seems to work correctly.
FOR /F "tokens=3" %%A IN ('"WMIC shadowcopy call create ClientAccessible,"C:\""^| FINDSTR /I ShadowID') DO SET ID=%%A
Can anyone explain to me why the first command will not work or what I am overlooking to make the first command work?
Yes, I know there are many other, including better, ways to achieve what I am wanting to do but for now I am just trying to better understand what I am missing here.
Thanks greatly
There are two problems in your code:
You stumbled upon a strange behaviour of FOR /F: it does not only remove the single quotes (apostrophies, '') around the command to parse, it also removes enclosing quotation marks if the first and last character of the remaining string are " both1, so the command line that is actually tried to be executed is WMIC shadowcopy call create ClientAccessible,"C:\""| FIND /I "ShadowID, which is invalid of course.
The WMIC command line is enclosed in quotation marks, so even if the above issue was not there, your code would fail, because the command interpreter tries to find a command or program named "WMIC shadowcopy call create ClientAccessible,", which does not exist of course.
So the corrected command line is:
FOR /F "tokens=3" %%A IN ('WMIC shadowcopy call create ClientAccessible^,"C:\" ^| FIND /I "ShadowID"') DO SET "ID=%%A"
Note that you need to escape the , herein (similar to the pipe).
1) You can affirm that by trying the command line FOR /F "tokens=3" %%A IN ('"WMIC" shadowcopy call create ClientAccessible^,"C:\" ^| FIND /I "ShadowID"') DO SET "ID=%%A", which fails, and FOR /F "tokens=3" %%A IN ('^""WMIC" shadowcopy call create ClientAccessible^,"C:\" ^| FIND /I "ShadowID"^"') DO SET "ID=%%A", which works because there are additional "" put around (they are escaped like ^" so that the command line does not need to be altered in terms of escaping; you could also state the " literally, but then you needed to unescape the , and the |).
In addition, I recommend to nest another FOR /F loop inside yours, because WMIC returns Unicode text, which could leave artefacts (orphaned carriage-return characters) when being parsed by FOR /F (as it expects ANSI text); an additional parsing phase eliminates such noise:
FOR /F "tokens=3" %%A IN ('WMIC shadowcopy call create ClientAccessible^,"C:\" ^| FIND /I "ShadowID"') DO FOR /F "delims=" %%B in ("%%A") DO SET "ID=%%B"
This method is credited to dbenham -- see his answer to Why is the FOR /f loop in this batch script evaluating a blank line? and also his external article WMIC and FOR /F : A fix for the trailing <CR> problem.
This is happening because the output of the WMCI command is in unicode. See this post Editing WMIC output format

CMD Batch - Find literal string

Got an interesting problem. I'm pulling a query on a registry to see if it exists - if it does, I go down one path. If it doesn't, I go down a seperate path. I'll put a code example at the bottom. Here's the question:
FIND doesn't have an /L switch I can use for literal interpretation. One of my settings is 4, and the other is 14. So 14 works great, 4 finds both 4 and 14.
Is there a way to have it find "4" rather than just 4? Using escape characters before the quotations or double quoting just makes it miss entirely.
This is just an example of what I mean. Names and values changed to protect the innocent. This is part of a much larger script, so 'enabledelayedexpansion' is necessary.
setlocal enabledelayedexpansion
set ValueOne=4
set ValueTwo=14
rem This section determines if additional specific concept settings are needed.
:ConceptCheck
rem DEBUG
echo CONCEPT CHECK
for /f "tokens=1" %%G in ('reg query hklm\software\SomeRegistry\ /v "Value" ^| find "!ValueTwo!"') do (
echo Value Two Found!
call :ValueTwoSetup)
for /f "tokens=1" %%G in ('reg query hklm\software\SomeRegistry\ /v "Value" ^| find "!ValueOne!"') do (
echo Value One Found!
call :ValueOneSetup)
goto :eof
When run, if the entry is ValueTwo, it works great. ValueOne calls both ValueTwo and itself, due to the fact that 14 has the number 4 in it, and find catches it. I've tried ""!ValueOne!"", but then it fails utterly. I've tried "^"!ValueOne!^"" to the same result. I CAN stick an 'goto :eof' at the end of the do call, but then I lose expandability, and I still have to monitor which value shows up first, which makes things more complicated and clumsy. I'll be dealing with around two hundred 'values' by the time I'm done, and they aren't sequential.
Thoughts?
findstr has \< and \> special characters to indicate word boundaries:
findstr /r /c:"\<!ValueOne!\>"
Alternatively you can instruct reg query to use exact match by adding /e, so no need for find:
reg query hklm\software\SomeRegistry /s /v "Value" /d /e /f "!ValueOne!" >nul
if not errorlevel 1 echo ValueOne Found! & call :ValueOneSetup

Windows 2003 batch script with pipe

I'm trying to write a batch script that will run every 15 minutes, check number of files in a directory and if that number is bigger then set limit, move all files to another directory. I would easily do this in bash script, but this is my first batch script.
I split this task in several steps:
Find number of files in directory.
I managed to do this with this command:
dir/b/a-d d:\test\test2 | find /v /c "::"
Next thing is to assign output of this command to some variable so I can compare it with my desired limit. This is where problem starts.
ECHO OFF
setlocal enableextensions
FOR /F "tokens=* USEBACKQ" %%a IN (`dir/b/a-d d:\test\test2 ^| find /v /c "::"`)
DO (#SET NUMFIL=%%a)
ECHO %NUMFIL%
endlocal
I'm getting: "| was unexpected at this time". Obviously, pipe is getting in the way. I found that it is special character and as such must be escaped with caret. After doing so, I'm getting: "The syntax of the command was incorrect." This is Windows server 2003.
3.After getting this problem solved, I plan to insert something like this:
IF %%NUMFIL%% > 20
(move "d:\test\test2\ti*" "d:\test\test2\dir\")
That would move all that files (all of them starts with "ti") to desired directory.
So my questions would be: what to do with #2 issue and will #3 work in this case?
Not sure ":: will work in your first case, since :: is unlikely to appear in a DIR output. A single colon would suffice, since the /c option of find counts the number of LINES in which the target string occurs.
The secret to the second problem is that the do keyword must occur on the same line as the closing-parenthesis of the IN clause. It is possible to break the structure into
FOR /F "tokens=* USEBACKQ" %%a IN (
' dir/b/a-d d:\test\test2 ^| find /v /c ":" '
) DO (SET NUMFIL=%%a)
Note the # is not required - it suppresses the command's being echoed, which is turned off by the initial #echo off (the # there suppresses the echoing of the ECHO OFF
Also, the parentheses around this set are not required. IF they are used, the open-parenthesis must occur on the same physical line as the do.
You also don't need to use usebackq since you have no need here to change the interpretation of quotes.
Third item - > is a redirector. For a comparison operator, use one of EQU GEQ LSS LEQ GTR NEQ depending on comparison required.
And again, the open-parenthesis must be on the same line as the if. With an else, the close-parenthsis before the ELSE , the ELSE keyword and the open-parenthesis after must all be on the same physical line.
I think this should work. Note that it does not use backticks.
ECHO OFF
setlocal enableextensions
FOR /F %%a IN (' dir /b /a-d "d:\test\test2" ^| find /c /v "" ') DO SET NUMFIL=%%a
ECHO %NUMFIL%
IF %NUMFIL% GTR 20 (move "d:\test\test2\ti*" "d:\test\test2\dir\")

This Supybot for windows batch install script needs to create another batch file

This Supybot for windows batch install script needs to create another batch file...
The Problem:
(1) I have a directory that has a file that ends with .conf
(2) There is only one file in this directory that ends with .conf
(3) But I don't know what this file starts with.. all I know is ????????.conf
(4) How do I set the filename.conf and remove the .conf part of the file name?
(5) As it is just the beginning of the filename that I need.
Example:
C:\runbot>find "supybot.ident: " | type *.conf > temp.txt
robotbot.conf
Outputs : robotbot.conf
The quest, is how do I set a variable=robotbot
=========================================================================
The Input was this file named "RootCode.conf" among many others
within the directory searched:
RootCode.conf
The Solution is:
FOR /F "tokens=1,2 delims=." %%a in ('FINDSTR /M "supybot.ident:" *.conf') DO SET USER=%%a&set dontneed=%%b
echo %USER%
pause
The Output is:
C:\runbot>FOR /F "tokens=1,2 delims=." %a in ('FINDSTR /M "supybot.ident:" *.con
f') DO SET USER=%a & set dontneed=%b
C:\runbot>SET USER=RootCode & set dontneed=conf
C:\runbot>echo RootCode
RootCode
C:\runbot>pause
Press any key to continue . . .
Winner... Special thanks Everyone
Your example of piping the output to typecommand is either wrong or useless. So I am assuming you mistyped and the real line was piping the other way around, and thus I am assuming that you are trying to find the filename of the file that contains the string "supybot.ident: ". In that case I would suggest to use findstr command instead.
FOR /F "tokens=*" %%a in ('FINDSTR /M "supybot.ident:" *.conf') DO SET USER=%%a
See HELP FINDSTR, HELP SET and HELP FOR for more information.
It's a bit unclear (to me, at least) what exactly you ask here. But if you need the output of a command, then use for /f:
for /f "delims=" %%x in ('some command ^| line') do set somevar=%%x
Note that you need to escape shell metacharacters in the command line (as they need to survive one parsing pass). Also note that you cannot set a variable to contain more than one line of text.

Resources