Apologies for my poorly worded question and my scatterbrain workings. Essentially I want to set an unknown number of variables that are parsed from each line of a text file.
I have written batch file to create symbolic links for network shares to a C:\Volumes folder.
#echo off
echo:
set /p dest=ENTER FOLDER PATH:
set dest="%dest%"
net use %dest%
if not exist "C:\Volumes" MD "C:\Volumes"
for %%i in (%dest%) do (set "fold=%%~ni")
mklink /d "c:\VOLUMES\%fold%" "%dest%"
pause
What I want to try is the same theory but have the script point at a text file mounts.txt with a list of folder paths and for a for loop to cycle through the list make a symbolic link for each path in the list. I have toyed with counters and cannot get it working correctly. I don't think I am going about it the right way at all.
Contents of mounts.txt
\\10.19.10.238\Masters\Removed bin\Work here
\\10.19.10.241\Scanning\WIP\to process
This does not work:
#echo off
setlocal enableDelayedExpansion
set i=1
:add
Set /a "i+=1"
for /F "tokens=*" %%A in (mounts.txt) do (set dest%i%=%%A)
if exist %dest%%i% goto:add
echo %dest%
echo %dest%%i%
echo !dest!
echo !dest!%i%
pause
Nor this:
#echo off
setlocal enableDelayedExpansion
set i=0
For /F "Tokens=1* Delims=] EOL=" %%A In ('Find /N /V ""^<"mounts.txt"') Do (
set /a i=i+1
set "dest!i!=%%B"
)
For /l %%a in (1,1,4) do echo _dest%%a is !dest%%a!
For /l %%a in (1,1,4) do set dest%%a=!dest%%a!
echo !dest!
pause
I did get something like this to work to an extent but cannot figure out how to use the dest[1], dest[2] as variables in other processes further down in the script.
#echo off
setlocal enabledelayedexpansion
set counter=0
for /f "tokens=*" %%a In (mounts.txt) do (
set /a counter+=1
set "dest[!counter!]=%%a"
)
set dest[
And the list could be added to with many more. If %dest%n variables can be set, the use the same theory to set different %fold% variables based on each %dest%n then maybe the links can be set using the same process as the original script.
Any help is appreciated. Thank you.
If your question actually describes what you want to do, you don't need to set variables. Just use the lines from the text file with a for /f loop:
for /f "delims=" %%i in (mount.txt) do mklink /d "C:\VOLUMES\%%~ni" "%%i"
It's safer to quote the filename, especially if you want/need to use the FQFN. Therefore you need the usebackq option, else a quoted string will be processed as a string, not a filename:
for /f "usebackq delims=" %%i in ("C:\full path\mount.txt") do mklink /d "C:\VOLUMES\%%~ni" "%%i"
You seemingly want to dynamically set the variables as dummy array's and return results based on the line numbers. If so, use the counter you created to become the max of the for /L loop, here is an example by just echoing the results:
#echo off & set cnt=0
setlocal enabledelayedexpansion
for /F "usebackq delims=" %%i in ("mounts.txt") do (
set /a cnt+=1
set "var[!cnt!]=%%i"
)
for /L %%a in (1,1,!cnt!) do echo !var[%%a]!
Edit
As highlighted by #Compo in the comments; after the initial code block where we increment the %cnt% variable, we no longer require using delayedexpansion on the %cnt% variable specifically and can therefore use %cnt% instead of !cnt!:
#echo off & set cnt=0
setlocal enabledelayedexpansion
for /F "usebackq delims=" %%i in ("mounts.txt") do (
set /a cnt+=1
set "var[!cnt!]=%%i"
)
for /L %%a in (1,1,%cnt%) do echo !var[%%a]!
This is a courtesy example, just to show you how you could have still used find.exe, as in one of your examples, and additionally includes a different method of iterating the variables with unknown increments:
#Echo Off
SetLocal EnableExtensions
Rem The next line ensures that there are no variables defined with names beginning _
For /F "Delims==" %%G In ('"(Set _) 2>NUL"') Do Set "%%G="
Rem The next lines parse the directory paths content file and defines the incrementing variables
For /F "Tokens=1,* Delims=]" %%G In (
'"%SystemRoot%\System32\find.exe /N "\" 0< "C:\Users\roar\My Directory\mounts.txt" 2>NUL"'
) Do (
Set "_Path%%G]=%%H"
Set "_Name%%G]=%%~nxH"
)
Rem The next lines iterate the defined variables beginning _Path[ and runs commands against them
For /F "Tokens=2 Delims=[]" %%G In ('"(Set _Path[) 2>NUL"') Do (
SetLocal EnableDelayedExpansion
MkLink /D "C:\Volumes\!_Name[%%G]!" "!_Path[%%G]!"
EndLocal
)
Rem The next line undefines any previously defined variables named beginning with _
For /F "Delims==" %%G In ('"(Set _) 2>NUL"') Do Set "%%G="
Please note that is likely you may need to run this script elevated, in order for the MkLink command to create the symbolic links.
This is my first post and I am not very skilled with batch so sorry if I really mess up.
Basically I'm working on a little batch script where once run, the user inputs a file path and line number and the specified line of the specified file will be output to the command line. I have all my variables and commands working, and the command to specify the line of the text file works fine, its just when I put my variables in it doesn't work. Now I'm guessing what I'm doing is obviously wrong since I'm new to batch, but anyway here's my code:
#echo off
color b
:top
title specified line copy tool
echo input full path to txt file
set /P filepath=">"
cls
echo what line would you like to copy?
set /P lineoriginal=">"
set /A actualline=%lineoriginal%-1
for /F "skip=%actualline% delims=" %%i in (%filepath%) do if not defined output set "output=%%i"
echo %output%
pause
See if you can see what I did wrong, thanks.
From this link Windows Batch file to echo a specific line number
you can call this function like that : Call:ReadNthLine <File> <nLine>
: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 ECHO.%%B
EXIT /b
And your code can be re-written like that :
#echo off
color b
:top
cls
title specified line copy tool
echo input full path to txt file
set /P "filepath=>"
cls
echo what line would you like to copy ?
set /P "nLine=>"
cls
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 ECHO.%%B
EXIT /b
::***************************************************************************************
When I run the command REG Query HKLM /k /F "Command Processor" /s /e /c on cmd, I get this result:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Command Processor
End results: 2 match(s) found(s).
But in batch:
#echo off & setlocal ENABLEEXTENSIONS
for /f "tokens=*" %%a in ('REG Query HKLM /k /F "Command Processor" /s /e /c') do set "MyPath=%%a"
echo The path string value is "%MyPath%"
pause
When I execute this, I only get the last line:
The path string value is "End results: 2 match(s) found(s)."
What is wrong? I would like to get the path keys on variables.
The problem is obvious: you are overwriting the value of MyPath in the for /F loop, then you are printing (echo) the final value/line.
To get all lines (any arbitrary number) you could do the following:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
rem storing the path strings in `MyPath1`, `MyPath2`, etc.:
set /A count=0
for /F "delims=" %%A in (
'REG Query HKLM /K /F "Command Processor" /S /E /C ^
^| findstr /L /B /V /C:"End of search: "'
) do (
set /A count+=1
set "MyPath!count!=%%A"
)
rem extracting the previously stored path strings:
echo Total number of path strings: %count%
for /L %%B in (1,1,%count%) do (
echo The !count!. path string value is "!MyPath%%B!"
)
pause
endlocal
This constitutes a sort of array MaPath1, MyPath2, and so on, containing all matching path strings.
The findstr command is used to filter out the summary line End of search: (this might be adapted according to your system locale/language).
Note that the array is no longer available after the endlocal command.
I try to get a path over the regestry of windows. My Problem now is how do I get the Path out of MATLAB_ROOT_32?
for /F "tokens=* delims='C'" %%i IN ('reg query HKLM\SOFTWARE\WOW6432NODE\Mathworks\Matlab\7.9.1 /v MATLABROOT') do (set MATLAB_ROOT_32=%%i)
echo %MATLAB_ROOT_32%
set i=
rem GOTO Split1
rem :Split1
REM -- Split the result into MATLABROOT, REG_SZ and Folder using space as delimiter
for /f "tokens=1,2,3 delims='C'" %%a in ("%MATLAB_ROOT_32%") do set useless1=%%a&set useless2=%%b&set MATLAB_x32=%%c
echo %Matlab_x32%
The plan is to get the MATLAB Path in the Matlab_x32 variable.
This works for me:
#echo off
setlocal ENABLEEXTENSIONS
set MATLAB_VERSION=8.3
set KEY_NAME=HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432NODE\MathWorks\MATLAB\%MATLAB_VERSION%
set VALUE_NAME=MATLABROOT
for /F "usebackq tokens=2*" %%A IN (`reg query "%KEY_NAME%" /v "%VALUE_NAME%" 2^>nul ^| find "%VALUE_NAME%"`) do (
set MATLABROOT=%%B
)
echo %MATLABROOT%
Just change the Matlab version to whatever you're using and it should be fine. There are variations in the output from reg depending on the OS version, but this should cope (I think!)
I want to count the no of lines in a text file and then the value has to be stored into a environment variable. The command to count the no of lines is
findstr /R /N "^" file.txt | find /C ":"
I refered the question How to store the result of a command expression in a variable using bat scripts?
Then I tried,
set cmd="findstr /R /N "^" file.txt | find /C ":" "
I am getting the error message,
FIND: Parameter format not correct
How could i get rid of this error.
There is a much simpler way than all of these other methods.
find /v /c "" filename.ext
Holdover from the legacy MS-DOS days, apparently. More info here: https://devblogs.microsoft.com/oldnewthing/20110825-00/?p=9803
Example use:
adb shell pm list packages | find /v /c ""
If your android device is connected to your PC and you have the android SDK on your path, this prints out the number of apps installed on your device.
You could use the FOR /F loop, to assign the output to a variable.
I use the cmd-variable, so it's not neccessary to escape the pipe or other characters in the cmd-string, as the delayed expansion passes the string "unchanged" to the FOR-Loop.
#echo off
cls
setlocal EnableDelayedExpansion
set "cmd=findstr /R /N "^^" file.txt | find /C ":""
for /f %%a in ('!cmd!') do set number=%%a
echo %number%
Inspired by the previous posts,
a shorter way of doing so:
CMD.exe
C:\>FINDSTR /R /N "^.*$" file.txt | FIND /C ":"
The number of lines
Try it. It works in my console.
EDITED:
(the "$" sign removed)
FINDSTR /R /N "^.*" file.txt | FIND /C ":"
$ reduces the number by 1 because it is accepting the first row as Field name and then counting the number of rows.
Try this:
#Echo off
Set _File=file.txt
Set /a _Lines=0
For /f %%j in ('Find "" /v /c ^< %_File%') Do Set /a _Lines=%%j
Echo %_File% has %_Lines% lines.
It eliminates the extra FindStr and doesn't need expansion.
- edited to use ChrisJJ's redirect suggestion. Removal of the TYPE command makes it three times faster.
#Tony: You can even get rid of the type %file% command.
for /f "tokens=2 delims=:" %%a in ('find /c /v "" %_file%') do set /a _Lines=%%a
For long files this should be even quicker.
I usually use something more like this
for /f %%a in (%_file%) do (set /a Lines+=1)
for /f "usebackq" %A in (`TYPE c:\temp\file.txt ^| find /v /c "" `) do set numlines=%A
in a batch file, use %%A instead of %A
The perfect solution is:
FOR /F %%i IN ('TYPE "Text file.txt" ^| FIND /C /V ""') DO SET Lines=%%i
I found this solution to work best for creating a log file that maintains itself:
setlocal enabledelayedexpansion
SET /A maxlines= 10
set "cmd=findstr /R /N "^^" "filename.txt" | find /C ":""
for /f %%a in ('!cmd!') do set linecount=%%a
GOTO NEXT
:NEXT
FOR /F %%A IN ("filename.txt") DO (
IF %linecount% GEQ %maxlines% GOTO ExitLoop
echo %clientname% %Date% %Time% >> "filename.txt")
EXIT
:ExitLoop
echo %clientname% %Date% %Time% > "filename.txt"
EXIT
Environmental variables included are %clientname% the computername of the remote client %Date% is the current date and %Time% the current time. :NEXT is called after getting the number of lines in the file. If the file line count is greater than the %maxlines% variable it goes to the :EXITLOOP where it overwrites the file, creating a new one with the first line of information. if it is less than the %maxlines% variable it simply adds the line to the current file.
You don't need to use find.
#echo off
set /a counter=0
for /f %%a in (filename) do set /a counter+=1
echo Number of lines: %counter%
This iterates all lines in the file and increases the counter variable by 1 for each line.
The :countLines subroutine below accepts two parameters: a variable name; and a filename. The number of lines in the file are counted, the result is stored in the variable, and the result is passed back to the main program.
The code has the following features:
Reads files with Windows or Unix line endings.
Handles Unicode as well as ANSI/ASCII text files.
Copes with extremely long lines.
Isn’t fazed by the null character.
Raises an error on reading an empty file.
Counts beyond the Batch max int limit of (31^2)-1.
#echo off & setLocal enableExtensions disableDelayedExpansion
call :countLines noOfLines "%~1" || (
>&2 echo(file "%~nx1" is empty & goto end
) %= cond exec =%
echo(file "%~nx1" has %noOfLines% line(s)
:end - exit program with appropriate errorLevel
endLocal & goto :EOF
:countLines result= "%file%"
:: counts the number of lines in a file
setLocal disableDelayedExpansion
(set "lc=0" & call)
for /f "delims=:" %%N in ('
cmd /d /a /c type "%~2" ^^^& ^<nul set /p "=#" ^| (^
2^>nul findStr /n "^" ^&^& echo(^) ^| ^
findStr /blv 1: ^| 2^>nul findStr /lnxc:" "
') do (set "lc=%%N" & call;) %= for /f =%
endlocal & set "%1=%lc%"
exit /b %errorLevel% %= countLines =%
I know it looks hideous, but it covers most edge-cases and is surprisingly fast.
Just:
c:\>(for /r %f in (*.java) do #type %f ) | find /c /v ""
Font: https://superuser.com/questions/959036/what-is-the-windows-equivalent-of-wc-l
One nice surprise is for one who has git bash on his windows: just plain old linux wc -l <filename> will works for you there
In the below code, the variable name are SalaryCount and TaxCount
#ECHO OFF
echo Process started, please wait...
for /f %%C in ('Find /V /C "" ^< "D:\Trial\Salary.txt"') do set SalaryCount=%%C
echo Salary,%SalaryCount%
for /f %%C in ('Find /V /C "" ^< "D:\Trial\Tax.txt"') do set TaxCount=%%C
echo Tax,%TaxCount%
Now if you need to output these values to a csv file, you could use the below code.
#ECHO OFF
cd "D:\CSVOutputPath\"
echo Process started, please wait...
echo FILENAME,FILECOUNT> SUMMARY.csv
for /f %%C in ('Find /V /C "" ^< "D:\Trial\Salary.txt"') do set Count=%%C
echo Salary,%Count%>> SUMMARY.csv
for /f %%C in ('Find /V /C "" ^< "D:\Trial\Tax.txt"') do set Count=%%C
echo Tax,%Count%>> SUMMARY.csv
The > will overwrite the existing content of the file and the >> will append the new data to existing data. The CSV will be generated in D:\CSVOutputPath
You can pipe the output of type into find inside the in(…) clause of a for /f loop:
for /f %%A in ('
type "%~dpf1" ^| find /c /v ""
') do set "lineCount=%%A"
But the pipe starts a subshell, which slows things down.
Or, you could redirect input from the file into find like so:
for /f %%A in ('
find /c /v "" ^< "%~dpf1"
') do set "lineCount=%%A"
But this approach will give you an answer 1 less than the actual number of lines if the file ends with one or more blank lines, as teased out by the late foxidrive in counting lines in a file.
And then again, you could always try:
find /c /v "" example.txt
The trouble is, the output from the above command looks like this:
---------- EXAMPLE.TXT: 511
You could split the string on the colon to get the count, but there might be more than one colon if the filename had a full path.
Here’s my take on that problem:
for /f "delims=" %%A in ('
find /c /v "" "%~1"
') do for %%B in (%%A) do set "lineCount=%%B"
This will always store the count in the variable.
Just one last little problem… find treats null characters as newlines. So if sneaky nulls crept into your text file, or if you want to count the lines in a Unicode file, this answer isn’t for you.
You can also try
set n=0 & for /f "tokens=*" %a in (text.txt) do set/a n=!n!+1
echo !n!
You can also mark with a wildcard symbol * to facilitate group files to count.
Z:\SQLData>find /c /v "" FR_OP133_OCCURENCES_COUNT_PER_DOCUMENTS_*.txt
Result
---------- FR_OP133_OCCURENCES_COUNT_PER_DOCUMENTS_AVIFRS01_V1.TXT: 2041
---------- FR_OP133_OCCURENCES_COUNT_PER_DOCUMENTS_AVIOST00_V1.TXT: 315938
---------- FR_OP133_OCCURENCES_COUNT_PER_DOCUMENTS_AVIFRS00_V1.TXT: 0
---------- FR_OP133_OCCURENCES_COUNT_PER_DOCUMENTS_CNTPTF00_V1.TXT: 277