Question

I am looking for a way in a Windows batch file to find if a file contains the word Shutdown a given number of times.

I have tried this using FINDSTR:

 FINDSTR /r .*Shutdown.*{5} file.txt

This doesn't seem to work, but if I remove the {5} it executes successfully.

Also I would eventually like the 5 to be a variable, presumably this is possible with some sort of dynamic command?

Thanks

Was it helpful?

Solution 2

.*Shutdown.*Shutdown.*Shutdown.*Shutdown.*Shutdown.*

would seem to be the only way for FINDSTR

srsly.


Test batch:

@ECHO OFF
SETLOCAL
FOR /f "delims=" %%i IN (f5shutdown.txt) DO (
 ECHO %%i|FINDSTR /r .*Shutdown.*Shutdown.*Shutdown.*Shutdown.*Shutdown.* >NUL
 IF ERRORLEVEL 1 ECHO FAILED IN "%%i"
 IF NOT ERRORLEVEL 1 ECHO FOUND  IN "%%i"
)

GOTO :eof

Test textfile in f5shutdown.txt

Shutdown
Shutdown Shutdown
Shutdown Shutdown Shutdown Shutdown
Shutdown Shutdown Shutdown Shutdown Shutdown
Shutdown already !Shutdown Shutdown Shutdown Shutdown now
You should now Shutdown Shutdown Shutdown Shutdown Shutdown
ShutdownShutdownShutdownShutdownShutdown
OK, don't shutdown then...

Result:

FAILED IN "Shutdown"
FAILED IN "Shutdown Shutdown"
FAILED IN "Shutdown Shutdown Shutdown Shutdown"
FOUND  IN "Shutdown Shutdown Shutdown Shutdown Shutdown"
FOUND  IN "Shutdown already !Shutdown Shutdown Shutdown Shutdown now"
FOUND  IN "You should now Shutdown Shutdown Shutdown Shutdown Shutdown"
FOUND  IN "ShutdownShutdownShutdownShutdownShutdown"
FAILED IN "OK, don't shutdown then..."

Works for me (W7)


Ah - perhaps you meant "occurs on 5 (or whatever) lines or "occurs 5 times in the file"...

@ECHO OFF
SETLOCAL
FOR /f "delims=" %%i IN (f5shutdown.txt) DO (
 ECHO %%i|FINDSTR /r .*Shutdown.*Shutdown.*Shutdown.*Shutdown.*Shutdown.* >NUL
 IF ERRORLEVEL 1 ECHO FAILED IN "%%i"
 IF NOT ERRORLEVEL 1 ECHO FOUND  IN "%%i"
)

:: For 'shutdown' on n different lines: (assuming case-insensitive)
FOR /f %%i IN ('FIND /i /c "shutdown" ^<f5shutdown.txt') DO SET shutdowns=%%i
ECHO Second method: %shutdowns% lines found with "Shutdown"

:: For 'shutdown' occurrences (assuming case-insensitive)
SET /a shutdowns=0
FOR /f "delims=" %%i IN (f5shutdown.txt) DO (
 SET line=%%i
 CALL :findem
)
ECHO Third method found "Shutdown" %shutdowns% times
GOTO :eof

:findem
SET line=%line:"=%
SET after=%line:*shutdown=%
IF NOT DEFINED after SET /a shutdowns+=1&GOTO :EOF 
if NOT "%line%"=="%after%" SET "line=%after%"&SET /a shutdowns+=1&GOTO findem
GOTO :eof

(I added an extra non-shutdown-containing line for the test. Found 8 lines and 28 occurrences)

OTHER TIPS

It is possible to use FINDSTR to detect if "Shutdown" appears 5 or more times anywhere within a file. All the information you need is contained within What are the undocumented features and limitations of the Windows FINDSTR command?, but it is more than a bit tricky and not at all obvious.

A regex search can match multiple instances of Shutdown across multiple lines, as long as all intervening characters, including carriage return and linefeed characters, are matched by an appropriate character class range. I cannot post the characters required here, so I will use symbolic notation within angle brackets.

The following regex expression will match any byte character except 0xFF (decimal 255). It consists of a character class expression with two ranges and a gap in the middle for 0xFF. The gap is critical because FINDSTR will fail (and possibly hang) if 0xFF is included:

[<0x01>-<space><tab>-<0xEA>]

You might think the expression should be [<0x01>-<0xFE>], but that does not work because FINDSTR does not collate characters by the numeric code value.

So to look for 5 or more instances of Shutdown anywhere within the file, you would need the following regex search:

Shutdown[<0x01>-<space><tab>-<0xEA>]*Shutdown[<0x01>-<space><tab>-<0xEA>]*Shutdown[<0x01>-<space><tab>-<0xEA>]*Shutdown[<0x01>-<space><tab>-<0xEA>]*Shutdown

The 0xEA (decimal 234) character is an extended ASCII character, and extended ASCII cannot be included on the command line of a FINDSTR search. So the search string must be put in an external file and the /G:file option must be used.

Here is a complete batch script that takes the minimum number of Shutdown instances to search for as the 1st argument, and the name of the file to search as the 2nd argument. Again I use symbolic notation within angle brackets in place of the actual characters needed.

@echo off
set count=%1
set file=%2
setlocal enableDelayedExpansion
set "search="
for /l %%N in (1 1 %count%) do set "search=!search!Shutdown[<0x01>-<space><tab>-<0xEA>]*"
set "search=!search:~0,-9!"
echo(!search!>search.txt
findstr /rg:search.txt %file% >nul&&echo FOUND||echo NOT found

The maximum supported count is limited by the maximum regex string length. For XP the max regex length is 127 bytes, equating to a count of 7. On Vista and Windows 7 the max regex length is 254 bytes, which should support a count of 15. But my testing on Windows 7 only supported a count up to 12. Additional tests reveal the max length is affected by how many string literals and character classes appear, as well as the relative placement of each. But I haven't been able to figure out an exact formula.


If you don't want to use an external file, then the following regex expression is almost as good. It matches any characters except for the following extended ASCII hex codes: 0xE0, 0xE2, 0xE3, 0xE4, 0xE5, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xED, 0xEE, 0xFF.

[<0x01>-<space><tab>-Z]

The full regex search would be:

Shutdown[<0x01>-<space><tab>-Z]*Shutdown[<0x01>-<space><tab>-Z]*Shutdown[<0x01>-<space><tab>-Z]*Shutdown[<0x01>-<space><tab>-Z]*Shutdown

And here is the complete batch script:

@echo off
setlocal enableDelayedExpansion
set count=%1
set file=%2
set "search="
for /l %%N in (1 1 %count%) do set "search=!search!Shutdown[<0x01>-<space><tab>-Z]*"
set "search=!search:~0,-9!"
findstr /rc:"!search!" %file% >nul&&echo FOUND||echo NOT found

This should detect when shutdown is on only 5 lines in the file.txt

@echo off
for /f %%a in ('find /i /c "shutdown" ^< "file.txt" ') do if %%a EQU 5 echo found it 5 times
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top