Parsing a delimited config file using FOR on Windows - windows

I have a java properties file to parse, it contains key value pairs of the form key=value, one on each line.
After digging around on the site, I've found this site that explains the FOR syntax, and also this question.
I constructed the following line to get the value of the backupdir.windows property in config.properties:
for /f "delims== tokens=2" %i in ('findstr backupdir.windows= config.properties') do #echo %i
The above works if you type it at the command prompt, but if I save it as a file 'test.cmd' and then execute that, I get 'i was unexpected at this time.'
Same thing happens if I change the extension to .bat (in case doing so would make it use
earlier MSDOS syntax).
What's going wrong here? I'm running Windows 7.

Better to do it like this:
#echo off
for /f "tokens=2 delims==" %%a in ('findstr /b /i "backupdir.windows" config.properties') do echo %%a

it needs to be %%i in a batch file. And just %i on the command line.

Related

Windows Batch: command result as command parameter

I have a curstom command that is an query language interpretor. And the file contains some queries to execute.
I want to execute this custom command by passing the whole file content as parameter with a single command.
For exemple somethink like :
myCustomCmd %type params.txt%
Is it possible ?
Thanks
for /f "usebackq delims=" %%a in ("params.txt") do myCustomCmd %%a
should draw that line from the file and use it as a parameter for you command.
Had you given us a context, I'd be able to provide more information.
Ah - you want "the entire file content" as the parameter - a requirement you edited-in five minutes after I'd posted this response...
#echo off
setlocal enabledelayedexpansion
set "params="
for /f "usebackq delims=" %%a in ("params.txt") do set "params=!params! %%a"
myCustomCmd %params%
That should fix the problem - in the absence of an example params.txt file.

I need a windows command line script that takes an output, edits it and creates an environmental variable

I have Asset tags embedded in BIOS. I use
wmic SYSTEMENCLOSURE get SMBiosAssetTag
This pulls the information I want but it is not formatted well:
SMBIOSAssetTag
11886
I need to just have those 5 numbers and nothing else. I will then use that variable to name the computer with a first logon script. I have spent hours on this, and I could have been done in 3 minutes if this was linux.
Note: I can't put linux tools on these builds :-(
Using
WMIC SYSTEMENCLOSURE GET SMBiosAssetTag /FORMAT:VALUE
will make a better output:
(some empty lines)
SMBIOSAssetTag=CZC1296FLD
(some empty lines)
So, in batch you may just
FOR /F "TOKENS=1,* DELIMS==" %%v IN (WMIC SYSTEMENCLOSURE GET SMBiosAssetTag /FORMAT:VALUE) DO IF /I "%%v" == "SMBIOSAssetTag" SET SMBIOSAssetTag=%%w
Side note: hard part in WMIC output is handling empty lines.
This will work, tested it myself:
for /f "eol=S" %%a in ('wmic SYSTEMENCLOSURE get SMBiosAssetTag^|sort') do (set var=%%a)
It works fine.
Mona
for /f "delims=" %%a in ('wmic SYSTEMENCLOSURE get SMBiosAssetTag') do for /f %%b in ("%%a") do set "var=%%b"
echo %var%

Findstr command in for-loop stops after a certain line

I have this snippet of script:
for /F "tokens=1* delims=:" %%a in ('findstr /N /C:"%SECTION%" /C:"%TARGET%" %BASE%') do (
:: Stuff:
)
echo Search Parameters not found
...where SECTION and TARGET are two search parameters. The BASE file is approximately 16,000 lines.
Here's my problem:
When I execute the for-loop inside a batch script, it searches for 2397 lines exactly, then just gives up. However, if I run the findstr command manually, it will search all lines as expected.
Any ideas?
Does this fail for you? It works here in Win 8 and a XP Pro VM to print 16,000 lines.
#echo off
(for /l %%a in (1,1,16000) do #echo 0123456789012345678901234567890123456789)>file
SET "section=123"
SET "target=456"
SET "base=file"
ECHO start
for /F "tokens=1* delims=:" %%a in ('findstr /NC:"%SECTION%" /C:"%TARGET%" "%BASE%"') do (
ECHO %%a
)
pause
Fool's mistake - upon changes of versions, the location of a certain file shifted. So while I thought my search for the file was correct, it actually ended up retrieving a file in similar name, but not the same file (MotionBase.class.asasm vs what I needed: BASE.class.asasm)
Thought I checked the location before submitting this question, but apparently not.

Why is the FOR /f loop in this batch script evaluating a blank line?

I'm trying to write a batch script that obtains (among other things) a list of all of the disk drives the computer has. The basic code looks something like this:
REM Build the list of disk drives to monitor
SETLOCAL enabledelayedexpansion
FOR /f "skip=1 tokens=1 delims=:" %%a in ('"WMIC logicaldisk WHERE drivetype=3 GET deviceid"') do (
SET "DISK_DATABASES=!DISK_DATABASES!%%a|"
SET "DRIVES_TO_MONITOR=!DRIVES_TO_MONITOR!%%a:\\|"
)
I pretty obviously build two lists with slightly different formats for use later. When I run this, however, the output I get looks something like this:
C|D|E||
C:\\|D:\\|E:\\|:\\|
Now, I expect the trailing pipe in both cases and I can manage that, but I'm really confused why there is an extra blank entry in there. If I run the wmic command manually, I can see that there is indeed a blank line at the end of the output, but my understanding is that /f was specifically supposed to ignore blank lines.
If I turn ECHO on, it looks like that last line is just coming in as a carriage return/newline or similar. Is there a way to do what I'm expecting? Am I missing something? I tried to write an if condition in the loop to exclude this last line, but it was... funky and never worked. I appreciate any/all help.
I just came over this topic. I've been using findstr /v to exclude empty lines:
FOR /f "usebackq skip=1 tokens=1 delims=:" %%a in (`WMIC logicaldisk WHERE "drivetype=3" GET deviceid ^| findstr /v /r "^$"`) do (
In this case the last iteration produces not an empty item, and you get your output of C|D|E|| only with echo %DISK_DATABASES%,
but echo !DISK_DATABASES! will output ||D|E|??
That's because the last element is a single <CR> character.
And <CR> characters are directly removed after the percent expansion, but not with delayed expansion.
You could avoid this, using the percent expansion to remove them
setlocal EnableDelayedExpansion
FOR /f "skip=1 tokens=1 delims=:" %%a in ('"WMIC logicaldisk WHERE drivetype=3 GET deviceid"') do (
set "item=%%a"
call :removeCR
if not "!item!"=="" (
SET "DISK_DATABASES=!DISK_DATABASES!!item!|"
SET "DRIVES_TO_MONITOR=!DRIVES_TO_MONITOR!!item!:\\|"
)
)
goto :eof
:removeCR
:removeCR
set "Item=%Item%"
exit /b
According to http://ss64.com/nt/for_f.html
Many of the newer commands and utilities (e.g. WMIC) output text files in unicode format, these cannot be read by the FOR command which expects ASCII.
To convert the file format use the TYPE command.
So it appears that WMIC and FOR don't play nice together.
I discovered a more efficient and more reliable method to strip the unwanted <CR> from the end of each line. No temp file, and no CALL needed.
I don't understand the mechanism of how FOR /F converts the WMIC unicode output into ASCII. Normally FOR /F cannot read unicode. But however it works, each converted line ends with <CR><CR><LF>. FOR /F breaks lines at each <LF>, and then if the last character in the line is <CR> it strips that last <CR>, in this case leaving behind the unwanted <CR>.
The solution is to simply pass each line through one more FOR /F :-)
#echo off
setlocal enableDelayedExpansion
for /f "skip=1 delims=" %%A in (
'wmic logicaldisk where "drivetype=3" get deviceid'
) do for /f "tokens=1 delims=:" %%B in ("%%A") do (
set "disk_databases=!disk_databases!%%B|"
set "drives_to_monitor=!drives_to_monitor!%%B:\\|"
)
This method is more reliable then using normal expansion because you don't have to worry about quoting or escaping special characters. For example, The CALL method that uses normal expansion cannot handle a string like "this & that" & the other. But this method has no problem with such a string.
Add ^| findstr . and you will get only not blank lines
REM Build the list of disk drives to monitor
SETLOCAL enabledelayedexpansion
FOR /f "skip=1 tokens=1 delims=:" %%a in (
'"WMIC logicaldisk WHERE drivetype=3 GET deviceid" ^| findstr .') do (
SET "DISK_DATABASES=!DISK_DATABASES!%%a|"
SET "DRIVES_TO_MONITOR=!DRIVES_TO_MONITOR!%%a:\|"
)
My standard idiom for dealing with this is to write the output from WMIC to a temp file, then use TYPE (which reduces UTF16 to ASCII) to feed that into FOR, like this:
:: Standard environment setup
setlocal enabledelayedexpansion
:: Every variable whose name starts with "tf" will identify a temporary
:: file - remove any such variables inherited from the parent environment
for /f %%V in ('set tf') do set %%V=
:: Create some temporary filenames. Prefix all of them with this script's
:: own name to avoid clashes with those owned by other scripts.
for /l %%I in (1,1,4) set tf%%I="%temp%\%~n0-temp%%I.txt"
:: Use temp file to work around coding mismatch between WMIC out and FOR in
wmic product where "name like 'Microsoft Office %% 2010'" get packagecache >!tf1!
for /f "skip=1" %%P in ('type !tf1!') do if exist "%%~P" msiexec /x "%%~P" /passive /norestart
:: Before quitting script, clean up temporary files
for /f %%V in ('set tf') do if exist "%%~V" del /f /q "%%~V"
endlocal
Run the following command:
wmic blah /value | find "=" >> wherever
Output will be:
field=value
Note that there will be no extra lines.

How do you loop through each line in a text file using a windows batch file?

I would like to know how to loop through each line in a text file using a Windows batch file and process each line of text in succession.
I needed to process the entire line as a whole. Here is what I found to work.
for /F "tokens=*" %%A in (myfile.txt) do [process] %%A
The tokens keyword with an asterisk (*) will pull all text for the entire line. If you don't put in the asterisk it will only pull the first word on the line. I assume it has to do with spaces.
For Command on TechNet
If there are spaces in your file path, you need to use usebackq. For example.
for /F "usebackq tokens=*" %%A in ("my file.txt") do [process] %%A
From the Windows command line reference:
To parse a file, ignoring commented lines, type:
for /F "eol=; tokens=2,3* delims=," %i in (myfile.txt) do #echo %i %j %k
This command parses each line in Myfile.txt, ignoring lines that begin with a semicolon and passing the second and third token from each line to the FOR body (tokens are delimited by commas or spaces). The body of the FOR statement references %i to get the second token, %j to get the third token, and %k to get all of the remaining tokens.
If the file names that you supply contain spaces, use quotation marks around the text (for example, "File Name"). To use quotation marks, you must use usebackq. Otherwise, the quotation marks are interpreted as defining a literal string to parse.
By the way, you can find the command-line help file on most Windows systems at:
"C:\WINDOWS\Help\ntcmds.chm"
In a Batch File you MUST use %% instead of % : (Type help for)
for /F "tokens=1,2,3" %%i in (myfile.txt) do call :process %%i %%j %%k
goto thenextstep
:process
set VAR1=%1
set VAR2=%2
set VAR3=%3
COMMANDS TO PROCESS INFORMATION
goto :EOF
What this does:
The "do call :process %%i %%j %%k" at the end of the for command passes the information acquired in the for command from myfile.txt to the "process" 'subroutine'.
When you're using the for command in a batch program, you need to use double % signs for the variables.
The following lines pass those variables from the for command to the process 'sub routine' and allow you to process this information.
set VAR1=%1
set VAR2=%2
set VAR3=%3
I have some pretty advanced uses of this exact setup that I would be willing to share if further examples are needed. Add in your EOL or Delims as needed of course.
Improving the first "FOR /F.." answer:
What I had to do was to call execute every script listed in MyList.txt, so it worked for me:
for /F "tokens=*" %A in (MyList.txt) do CALL %A ARG1
--OR, if you wish to do it over the multiple line:
for /F "tokens=*" %A in (MuList.txt) do (
ECHO Processing %A....
CALL %A ARG1
)
Edit: The example given above is for executing FOR loop from command-prompt; from a batch-script, an extra % needs to be added, as shown below:
---START of MyScript.bat---
#echo off
for /F "tokens=*" %%A in ( MyList.TXT) do (
ECHO Processing %%A....
CALL %%A ARG1
)
#echo on
;---END of MyScript.bat---
#MrKraus's answer is instructive. Further, let me add that if you want to load a file located in the same directory as the batch file, prefix the file name with %~dp0. Here is an example:
cd /d %~dp0
for /F "tokens=*" %%A in (myfile.txt) do [process] %%A
NB:: If your file name or directory (e.g. myfile.txt in the above example) has a space (e.g. 'my file.txt' or 'c:\Program Files'), use:
for /F "tokens=*" %%A in ('type "my file.txt"') do [process] %%A
, with the type keyword calling the type program, which displays the contents of a text file. If you don't want to suffer the overhead of calling the type command you should change the directory to the text file's directory. Note that type is still required for file names with spaces.
I hope this helps someone!
The accepted answer is good, but has two limitations.
It drops empty lines and lines beginning with ;
To read lines of any content, you need the delayed expansion toggling technic.
#echo off
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ text.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!"
echo(!var!
ENDLOCAL
)
Findstr is used to prefix each line with the line number and a colon, so empty lines aren't empty anymore.
DelayedExpansion needs to be disabled, when accessing the %%a parameter, else exclamation marks ! and carets ^ will be lost, as they have special meanings in that mode.
But to remove the line number from the line, the delayed expansion needs to be enabled.
set "var=!var:*:=!" removes all up to the first colon (using delims=: would remove also all colons at the beginning of a line, not only the one from findstr).
The endlocal disables the delayed expansion again for the next line.
The only limitation is now the line length limit of ~8191, but there seems no way to overcome this.
Or, you may exclude the options in quotes:
FOR /F %%i IN (myfile.txt) DO ECHO %%i
Here's a bat file I wrote to execute all SQL scripts in a folder:
REM ******************************************************************
REM Runs all *.sql scripts sorted by filename in the current folder.
REM To use integrated auth change -U <user> -P <password> to -E
REM ******************************************************************
dir /B /O:n *.sql > RunSqlScripts.tmp
for /F %%A in (RunSqlScripts.tmp) do osql -S (local) -d DEFAULT_DATABASE_NAME -U USERNAME_GOES_HERE -P PASSWORD_GOES_HERE -i %%A
del RunSqlScripts.tmp
If you have an NT-family Windows (one with cmd.exe as the shell), try the FOR /F command.
The accepted anwser using cmd.exe and
for /F "tokens=*" %F in (file.txt) do whatever "%F" ...
works only for "normal" files. It fails miserably with huge files.
For big files, you may need to use Powershell and something like this:
[IO.File]::ReadLines("file.txt") | ForEach-Object { whatever "$_" }
or if you have enough memory:
foreach($line in [System.IO.File]::ReadLines("file.txt")) { whatever "$line" }
This worked for me with a 250 MB file containing over 2 million lines, where the for /F ... command got stuck after a few thousand lines.
For the differences between foreach and ForEach-Object, see Getting to Know ForEach and ForEach-Object.
(credits: Read file line by line in PowerShell )
Modded examples here to list our Rails apps on Heroku - thanks!
cmd /C "heroku list > heroku_apps.txt"
find /v "=" heroku_apps.txt | find /v ".TXT" | findstr /r /v /c:"^$" > heroku_apps_list.txt
for /F "tokens=1" %%i in (heroku_apps_list.txt) do heroku run bundle show rails --app %%i
Full code here.
To print all lines in text file from command line (with delayedExpansion):
set input="path/to/file.txt"
for /f "tokens=* delims=[" %i in ('type "%input%" ^| find /v /n ""') do (
set a=%i
set a=!a:*]=]!
echo:!a:~1!)
Works with leading whitespace, blank lines, whitespace lines.
Tested on Win 10 CMD

Resources