How to retrieve substring from a string in Windows batch file? - windows

How do I retrieve the string "C:\Program Files (x86)\Stupid\MS\" from the following input?
HKEY_CURRENT_USER\Software\Stupid\MS`
installpath REG_SZ C:\Program Files (x86)\Stupid\MS\`
please use windows bat file.
My way:
#echo off
Setlocal enabledelayedexpansion
for /f "tokens=2,* delims=:" %%i in ('reg query "HKEY_CURRENT_USER\Software\Stupid\MS" /v "installpath"') do (
echo %%i
)
pause
the result is : \Program Files (x86)\Stupid\MS\

req query "HKEY_CURRENT_USER\Software\Stupid\MS" /v "installpath"
returns this on my xp (sorry I don't have anything more recent at the moment)
! REG.EXE VERSION 3.0
HKEY_CURRENT_USER\Software\Stupid\MS
installpath REG_SZ C:\Program Files (x86)\Stupid\MS
When using delim's default value (a space) what we actually need is the third and following tokens from the last line. "third and following" is tokens=3*. The third token will be available in %%i, the "and following" in %%j. This letter is automatically assigned.
Unfortunately the first line also has a third and following token, so we need to exclude the first line. We can do that by using the eol option to exclude lines starting with "!". "Setlocal enabledelayedexpansion" doesn't change anything in this litte batch file so I dropped it.
Summary: this works for me:
#echo off
for /f "eol=! tokens=3*" %%i in ('reg query "HKEY_CURRENT_USER\Software\Conceptworld\Piky\Settings" /v "installpath"') do echo %%i %%j

This should work - put a tab character in where it says TAB and leave the space too.
#echo off
for /f "tokens=2,* delims=:TAB " %%i in ('reg query "HKEY_CURRENT_USER\Software\Stupid\MS" /v "installpath"') do (
set "var=%%j"
)
echo "%var%"
pause

Related

Exclude all rows of a file of key strings contained in some other file

I am trying to write a Windows batch file where there are two files in concern.
The first file all.err contains logs of failed test cases like below:
`CHECK:FAIL,"It should have been DEST`"
`CHECK:FAIL,"It should have been XYZA`"
`CHECK:FAIL,"It should have been PRTS`"
`CHECK:FAIL,"It should have been ABCD`"
.....................................
We have another file exclude.txt which stores some string per line like:
XYZA
ABCD
I am trying to write a Windows batch script which can list all lines from all.err that do not contain any word in exclude.txt.
I am not able to understand how this can be implemented - any idea?
There is just one Windows command line necessary for this task as written by SomethingDark:
%SystemRoot%\System32\findstr.exe /I /L /V /G:exclude.txt all.err
The help output on running in a Windows command prompt window findstr /? explains the parameters /I (case-insensitive), /L (search strings are literal strings), /V (inverse matching output), /G (get search strings from file).
When using a for loop, you need to go through exclusions file first, get each line, then exclude these meta viariables from your search in the log file:
#echo off
for /f "delims=" %%i in (exclude.txt) do (
for /f "delims=" %%b in ('type all.log ^| findstr /V "%%i"') do echo(%%b
)
The first do code block is not needed, I simply posted it like that for readability, it simply can be:
#echo off
for /f "delims=" %%i in (exclude.txt) do for /f "delims=" %%b in ('type all.log ^| findstr /V "%%i"') do echo(%%b

Removing blank lines and spaces in text file using batch

I have a batch file which is checking the value of a registry key.
I have the file reading the value and deleting the blank line at the beginning of the file, but there are still spaces in the output which need removing.
The script appears not to read the output properly if it contains spaces.
Here is the code I am using:
#echo off
md c:\temp
md c:\temp\Reg_Test
reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto > c:\temp\Reg_test\AfterRegUpdate32.log
findstr /v /r /c:"^$" /c:"^\ *$" /c:"^\ *$" "C:\temp\Reg_Test\AfterRegUpdate32.log" >> "C:\temp\Reg_Test\AfterRegUpdate32.txt"
exit
It appears to do everything I need except for deleting the spaces. I know there is something simple I am missing here. Any help will be greatly appreciated.
Is this what you're trying to retrieve:
#Echo Off
MD "C:\temp\Reg_Test" 2>Nul
(For /F "EOL=H Tokens=2*" %%A In (
'Reg Query "HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" /V "SchUseStrongCrypto" 2^>Nul'
) Do Echo %%B)>"C:\temp\Reg_Test\AfterRegUpdate32.txt"

How to deal with an em dash in a filename

On a PC with Windows 7, I'm using a simple batch script to rename some Excel files, pre-pending their parent folder name:
for /f "delims=" %%i in ('dir /b /AD') do (
cd "%%i"
for /f "delims=" %%j in ('dir /b *.xl*') do ren "%%~j" "%%i_%%~j"
cd..
)
I noticed that some files generated an error, "System cannot find the specified file." These files all had an em dash (—) in the filename. After I changed the em dash to a regular hyphen (-), using Windows Explorer, the script worked fine on these files.
How can I help script the rename of these files?
Your problem is not with the batch variables: from the command line this works fine:
for %i in (*) do ren "%~i" "test_%~i"
but, as can be seen from:
for /f "delims=" %i in ('dir /b /a-d') do #echo ren "%~i" "test2_%~i"
dir /b is changing the em dash to a hyphen, and so the ren command clearly won't find the file to change.
For your examples you should find:
for /d %%i in (*) do (
and
for %%j in (*.xl*) do ...
should work fine.
If you need the dir /b for other reasons, I don't see a solution right now.
(I had a convoluted attempt exchanging all hyphens for question marks, using the "Environment variable substitution" and "delayed environment variable expansion" as described in SET /? and CMD /?, allowing any character to match, and then again use ren pattern matching to ignore the problem.
I.e.
SETLOCAL ENABLEDELAYEDEXPANSION
for /f "delims=" %%I in ('dir /b /a-d') do (
Set K=%%I
ren "!K:-=?!" "test2_!K:-=?!"
)
but ren * x* replaces the start of the files with x, so the above replaces the hyphens with the content at that location before test_ was inserted.
So the best this approach can do is convert the em dashes to hyphens with:
SETLOCAL ENABLEDELAYEDEXPANSION
for /f "delims=" %%I in ('dir /b /a-d') do (
Set K=%%I
ren "!K:-=?!" "test2_!K!"
)
)
And confirming it is the output of dir /b that is the problem: on the command line:
dir /b *—* > test.txt
where that — is an em dash, will only list the files with em dashes, but, in the output file, e.g. Notepad test.txt, you'll only find hyphens, and no em dashes.
BTW I've done all this testing on Windows 8.1 which VER displays as Microsoft Windows [Version 6.3.9600].
(As I mention above I did have ren * x* in this answer, but that replaces the first character with x rather than insert it, which I always thought ren did!)

Exclusion of files of certain extension

In a Windows cmd batch script named my.bat, I want to execute a command for all the files in the current directory except for the batch file my.bat.
I use below command in my.bat currently to run the command only for *.txt *.ppt, but really as new files of different extensions might be added to the folder and hence execution of this command by excluding one type of file extension (in my case *.bat) would be more readable/helpful.
FOR /F "delims=|" %%i IN ('dir /b *.txt *.ppt') DO echo %%i
Question is: How do I exclude that file alone with that particular file extension and make the for command execute on all files of all extensions except the excluded one?
FOR /F "tokens=* delims=|" %%i IN ('dir /b *.*') do if not %%~xi==.bat echo %%i
I have added tokens=* in as well otherwise you won't get full filenames if they have spaces.
To echo without the dot
setlocal enabledelayedexpansion
FOR /F "tokens=* delims=|" %%i IN ('dir /b *.*') do (
set e=%%~xi
set e=!e:.=!
echo !e!
)
This is providing that the file doesn't have any other dots, otherwise it will remove them too. This is a bit more sturdy than just removing the 4th character from the end though, as not all files have a 3 character extension.
You could pass the output of the dir /b command through findstr, like so:
FOR /F "delims=|" %%i IN ('dir /b ^| findstr /v /r "^my.bat$"') DO echo %%i
The /v option to findstr prints anything that doesn't match the parameter. The match is based on a regular expression that matches only lines that contain my.bat and nothing else.

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