If a case insensitive search is acceptable then the following is simpler and I presume significantly faster:
set "str= hand"
for /f ^"eol^=^
delims^=^" %%a in ('"findstr /i "/c:%str%" %file%"') do set "ln=%%a"&call :countStr
echo '%str%' appears %cnt% times in hands.txt (case insensitive)
if "!ln2!" neq "!ln!" (
set /a "cnt+=1"
endlocal & set cnt=%cnt%
HAND randomtext handrandomtext
; hand randomtext
' hand' appears 5 times in hands.txt (case insensitive)
I changed the search string to include a leading space and changed the text file to demonstrate issues with the FOR /F eol option. See the eol discussion embedded within Sorting tokens within a string
for more info. Note that the last hand in hands.txt should not be counted because it is not preceded by a space.
I also changed the text file to include uppercase to demonstrate that the search is indeed case insensitive. FINDSTR is by default case sensitive, but the string substitution technique that I used can only be case insensitive.
Using FINDSTR is still very worth while because we don't want to waste time parsing lines that don't have the search string anywhere within them.