So I am trying to create batch script that does a findstr of two variables. I am reading from a specific file where I need the variables from.
The variables I need are
NetPath=
NetPathmed=
And my goal is to use the two variables to do a network map drive. In the first findstr I need everything after the NetPath= and in the second I need just a specific amount of data from the string. A normal NetPathMed looks like this
NetPathmed=\\**IPaddress**:C:\folder\file.
I just need the IP address
For example the batch I created looks like this
cd: C:\folder\
set var1="findstr 'NetPath=' file.ini"
for /f "tokens=1,2 delims== " %%a in ("%var1%") do set net=%%a&set path=%%b
Set var2= "findstr 'NetPathMed' opsetup.ini"
for /f "tokens=1,2,3 delims==/ " %%c in ("%var2%") do set net=%%c&set path=%%d &set net=%%e
net use var1(driveletter) \var2(IPaddress)\network folder /persistent:yes
cd C:\folder\
set var1='findstr "NetPath=" file.ini'
for /f "tokens=1,* delims==" %%a in (%var1%) do set var1=%%b
Set var2='findstr "NetPathMed" opsetup.ini'
for /f "tokens=2,3 delims=\:" %%c in (%var2%) do ECHO elements %var1% %%c %%d: /persistent:yes
Well - fixed a bit. Very difficult to tell where the elements you are extracting from your files actually are and which you wish to assemble into your command.
Made worse by your using 'NetPathMedin your code butNetPathmedin the data line you have given. If you don't use the/iswitch,findstr` is case-sensitive.
Other errors:
cd: should not have a :.
The command within the parentheses of the for /f should be enclosed in SINGLE quotes. FINDSTR likes "double quotes"
I couldn't tell whether you wanted the data to be placed in var1 and var2 or what - an example of the relevant contents of the two files and the required command to be generated would have been helpful.
I chose to assign all of the text after the = in the selected line from the first file into var1 (because that's what you said)
The first part in %%a is token1 = NetPath (not used) and the second token (*=the rest of the line) appears in the next metavariable (%%b)
Similarly, parsing the EXACT DATA that you posted, you are only using the second and third tokens
token1 is NetPathmed=
token2 is **IPaddress**
token3 is C
token 4 is \folder\file. I just need the IP address
Note that you specified / not \. Different animal. Chalk and cheese.
So - all you'd need to do is assemble the various elements %var1% %%c and %%d together with the fixed text you require, replace the echo with net use after testing and you should be off...
Related
I have a batch script to add new entries based on the given IP address:
#echo off
SET NEWLINE=^& echo.
set /p ipAddress=What is the IPv4 address of the instance?
FIND /C /I "storage.app.lab" %WINDIR%\system32\drivers\etc\hosts
IF %ERRORLEVEL% NEQ 0 ECHO %NEWLINE%^%ipAddress% storage.app.lab>>%WINDIR%\System32\drivers\etc\hosts
FIND /C /I "home.app.lab" %WINDIR%\system32\drivers\etc\hosts
IF %ERRORLEVEL% NEQ 0 ECHO %NEWLINE%^%ipAddress% home.app.lab>>%WINDIR%\System32\drivers\etc\hosts
FIND /C /I "api.app.lab" %WINDIR%\system32\drivers\etc\hosts
IF %ERRORLEVEL% NEQ 0 ECHO %NEWLINE%^%ipAddress% api.app.lab>>%WINDIR%\System32\drivers\etc\hosts
pause
However, I want to be able to overwrite existing entries with the domain name if a new ip address is entered. For example, if an entry with the domain name of "storage.app.lab" already exists, replace it with the new IP address.
How can I achieve that without using a backup hosts file?
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q64587777.txt"
:: I'll just use a fixed string for the IPaddress
set "IPaddress=User-input IP address"
:: remove variables starting #
FOR /F "delims==" %%a In ('set # 2^>Nul') DO SET "%%a="
FOR /f "tokens=1*delims=:" %%a IN (
'findstr /v /N /L /C:"storage.app.lab" /C:"home.app.lab" /C:"api.app.lab" "%filename1%"'
) DO set "#%%a=%%b"
(
FOR /F "tokens=1*delims==" %%a In ('set # 2^>Nul') DO echo %%b
for %%a in ("storage.app.lab" "home.app.lab" "api.app.lab") do echo %IPaddress% %%~a
)>"%filename1%"
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances. The listing uses a setting that suits my system.
I used a file named q64587777.txt containing some dummy data for my testing.
The first few lines simply establish filename variables for testing, and a recognisable string to save re-entering data in testing.
The procedure will use variables named #* for temporary storage of the "other" lines in the file in question, so first clear out any variables that may exist that start #.
Then execute findstr and "print" lines that do NOT contain (/V) any of the /L literal strings provided as /c:"string-to-EXclude" and /N number thos lines with a leading serial number followed by a colon.
The for /f tokenises the line using the : separator as a delimiter and assigning the line number to %%a (token 1) and the remainder of the line (the data in question) to %%b. Set the environment variable #%%a to the lines found.
Then use the same principle on a set # list, which will list all variables starting # in the format #1=line one, delimiting on = and selecting the 2nd token, which is the line data originally read from the file.
And add the three new lines by construction.
Parenthesising the two for statements together gathers the echoed output which is then redirected to the original file, overwriting it.
Note that OP's code appended the (up to) three new lines. The requirement is (apparently) that the 3 lines will appear in the file, replacing any existing data for those three entries.
I am building a Username and Password function for a batch file, and I have the system to read from 2 text files, Uname and Pass, and find the usernames and passwords, but the system is pulling any password listed in Pass. How can I read the line the username is on, set the password to only accept the corresponding line in the Pass text file?
FOR /F "tokens=* delims=" %%x in (Users.txt) DO IF '%uname%'=='%%x' goto AdmCont
rem FOR /F "tokens=* delims=" %%x in (Pass.txt) DO IF '%code%'=='%%x' goto AdmCont
Here is a simpler solution:
for /f "delims=: tokens=1,2" %A IN ('findstr /n "%uname%" Users.txt') do ( #set "number_of_line=%A" && #set "_uname=%B" )
Or, using find instead of findstr (quite complicated):
for /f "eol=- delims=[] tokens=1-2" %A IN ('find /n "%uname%" Users.txt') do ( #set "number_of_line=%A" && #set "_uname=%B" )
As in your post you have requested batch file code (you have double percent signs (%%)) you can double the percent-signs of the variables.
Let me explain my code:
In both two loops, we parse output of commands. You should know the command-output-format and why using findstr is much simpler.
findstr
We use /n option with findstr which tells it to echo the line that found string specified.
After /n option, we specify string that should be searched in specified after file.
After that, we specify the file we want to search the specified string.
The output will be:
%line_number%:%content_of_line%
So, we parse it saying:
DON'T PARSE : symbol into token with delims=: option!
Access the line_number with %(%)A and content_of_line with %(%)B using tokens=1,2 option.
Well known: specify variable letter add IN, then command to be parsed and set to variables number of line and its content.
find
We use /n option with find which tells it to echo the line that found string specified.
After /n option, we specify string that should be searched in specified after file.
After that, we specify the file we want to search the specified string.
The syntax is quite similar, but the output is completely different!:
---------- %FILENAME_SPECIFIED_WITH_CAPITAL_LETTERS%
[%line_number%]%line_content%
So, here:
We ignore lines starting with - with eol=- option.
We don't parse [] symbols into tokens with delims=[].
We want to access line_number with %(%)A and line_content with %(%)B, so, we add tokens=1,2 option.
Then, continuing as above (well known).
For better understanding how these commands work, I suggest you to open a new cmd window and type:
for /?
find /?
findstr /?
Try some examples of yours with find and finstr to completely understand how they work.
Some interesting references for further reading:
https://ss64.com/nt/findstr.html
https://ss64.com/nt/for_cmd.html
https://ss64.com/nt/find.html
I have a situation here that is as followed:
I've extracted a registry value under HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders with folder locations.
The problem is that the code works for a path that has a space in it, but if i use the very same code for a path that has no spaces in it, the output is wrong.
I know it is related to tokens but i'm hoping there is a way to make the code work for both cases .
The code i currently have looks as followed:
FOR /F "tokens=2*" %I in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Startup ') DO echo "%J"
and the output:
"%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
On a side note: expanding %USERPROFILE% is no problem for me, i simply use the CALL function for that
Now, when changing the path of registry value Startup to something that doesn't have any spaces in it, the before mentioned code fails.
Hopefully someone has a way to make it work in both cases.
With best regards,
copyitright
One of the requirements of the for /f command usage is the correct use (when needed) of delims and tokens clauses. They have to be properly adapted to the format of the line(s) being processed.
Your problem here is that the output of the reg.exe command does not include a clear, unmistakable delimiter. We usually use the default space/tab delimiters to process the reg.exe output but as you have found, sometimes the general format has to been adapted to process different lines as
Cache REG_EXPAND_SZ %USERPROFILE%\AppData\Local\Microsoft\Windows\INetCache
My Pictures REG_EXPAND_SZ %USERPROFILE%\Pictures
In the second line the additional space present in the value name requires a different tokens clause when using space as delimiter.
And no, there is not any universal way of dealing with the output of the reg.exe command. You need to know what you request and adapt to it.
An alternative, if you know your value names will not include a underscore is to use it as a delimiter. This will split the line in the REG_* value type, leaving a token that can be splitted using the space as a delimiter
#echo off
setlocal enableextensions disabledelayedexpansion
for /f "skip=2 tokens=1,* delims=_" %%a in ('
reg query
"HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
/v "My Pictures"
') do for /f "tokens=1,*" %%c in ("%%b") do echo "%%d"
Another alternative is to use another way to retrieve the value. You can use wmic to query the registry. Something like (sorry, spanish locale)
W:\>wmic /NameSpace:\\root\default Class StdRegProv Call GetStringValue hDefKey="&H80000001" sSubKeyName="Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" sValueName="My Pictures"
Ejecutando (StdRegProv)->GetStringValue()
Ejecución correcta del método.
Parámetros de salida:
instance of __PARAMETERS
{
ReturnValue = 0;
sValue = "C:\\Users\\UserName\\Pictures";
};
This output can be processed by retrieving the sValue line and using the quotes as delimiters (not the only way, just an example)
#echo off
setlocal enableextensions disabledelayedexpansion
for /f tokens^=2^ delims^=^" %%a in ('
WMIC /NameSpace:\\root\default Class StdRegProv
Call GetExpandedStringValue
hDefKey^="&H80000001"
sSubKeyName^="Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
sValueName^="My Pictures"
^| find "sValue"
') do echo "%%~fa"
note: The wmic sample code uses the Shell Folders subkey instead of the User Shell Folders because the wmic was expanding %userprofile% to the system user profile folder and I'm not sure if this is a default/logic behaviour or it is a problem in my machine. When I have another machine at hand I will test it.
This solution does not "make FOR /F tokens more universal", but get the value placed after "REG_EXPAND_SZ " string instead that, IMHO, is what you want...
#echo off
setlocal
for /F "delims=" %%a in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Startup') do set "value=%%a"
set "value=%value:*REG_EXPAND_SZ =%"
echo "%value%"
reg.exe uses four consecutive SPACEs to separate value names, data types and values from each other in the output (after an empty line and the line holding the key):
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
Startup REG_EXPAND_SZ %USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
So, given that the value does never contain such four SPACEs on its own, you could replace them by a character that does never occur in the value either, then use this one as the delimiter, e. g., the |:
#echo off
rem // The `skip=2` option skips the empty line and the key from being iterated:
for /F "skip=2 delims=" %%R in ('
reg query ^
"HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" ^
/v "Startup"
') do (
rem // Store line of interest in environment variable:
set "LINE=%%R"
rem // Toggle delayed expansion to not lose exclamation marks:
setlocal EnableDelayedExpansion
rem /* Replace ` ` by `|` and use the latter as the delimiter character;
rem token 1 is dismissed but is included for the loop to iterate even in case
rem the 3rd token, namely the value, was empty: */
for /F "tokens=2,* delims=|" %%V in ("!LINE: =|!") do (
endlocal
echo(%%W
)
)
This approach fails in case the value name contains four consecutive SPACEs or the used delimiter character |.
Alternatively, you could search for the string 4 × SPACE + REG_, because all registry data types begin with REG_; then from the string behind that, remove everything up to the next four consecutive SPACEs to extract the value:
#echo off
rem /* The `eol=H` option skips the line with the key (`HKEY_*`) from being iterated;
rem the empty line is skipped anyway by `for /F`: */
for /F "delims= eol=H" %%R in ('
reg query ^
"HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" ^
/v "Startup"
') do (
rem // Store line of interest in environment variable:
set "LINE=%%R"
rem // Toggle delayed expansion to not lose exclamation marks:
setlocal EnableDelayedExpansion
rem /* Remove everything up to ` REG_`, so the value name is split off;
rem this works only because every value type begins with `REG_`: */
set "LINE=!LINE:* REG_=!"
rem // Then remove everything up to ` `, so the actual value remains:
echo(!LINE:* =!
endlocal
)
This approach fails in case the value name (not the value) contains four consecutive SPACEs followed by the string REG_.
Due to the fact that there are a very limited number of known registry data types, we could even search the line for these strings, preceded and followed by four SPACEs:
#echo off
rem /* The `eol=H` option skips the line with the key (`HKEY_*`) from being iterated;
rem the empty line is skipped anyway by `for /F`: */
for /F "delims= eol=H" %%R in ('
reg query ^
"HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" ^
/v "Startup"
') do (
rem // Store line of interest in environment variable:
set "LINE=%%R"
rem // Toggle delayed expansion to not lose exclamation marks:
setlocal EnableDelayedExpansion
rem /* Loop through the possible registry value data types, search the line for
rem ` ` + a data type name + ` ` and remove everything up to that: */
for %%T in (
REG_SZ,REG_MULTI_SZ,REG_EXPAND_SZ,REG_DWORD,REG_QWORD,REG_BINARY,REG_NONE
) do (
set "LINE=!LINE:* %%T =!"
)
echo(!LINE!
endlocal
)
Since it is very unlikely that the search strings occur in the value name and the value itself, I consider this as the most reliable method when using the reg command.
i currently have this command for a batch file
for /F "skip=1 tokens=1 delims=\n" %i in (stats.txt) do echo %i
with the contents of stats.txt being
Title = Subaru's Great Rehab Strategy
URL = http://dynasty-scans.com/chapters/subarus_great_rehab_strategy
Tags = Subaru x Tsukasa[|]Yuri[|]
No. of Pages = 3
^ NOTE: the final line is actually blank
the idea of the line of code is to return the 2nd line with URL. the end goal would be that i would run this line in some sort of loop going though a series of ~12000+ stats.txt files and collecting all the URL lines into a single file
but when i run the command i get this
as you can see it has skipped the first line but it's cutting off where the n in dynasty and outputting the last 3 lines.
now if i remove delims=\n i get the same 3 lines but i don't get the first word before the space which seems to indicate that the value of delims is what splits a line into "tokens" which then i just grab the first one (and space must be the default)
when i go into notepad++, open the Find and Replace Dialog, turn Search Mode to extended and look for "\r\n" i get taken to the end of each line which is why i chose delims to be \n assuming this would then make the entire line one token
So my question is How can i get all of the 2nd line only of my stats.txt file?
The for /f loop already treats the carriage return and / or line feed as an end-of-line. No need to specify it as a delimiter. With delims=\n you're actually saying that all literal backslashes and letter n's should be treated as token delimiters. If you want the whole line, what you want is "skip=1 delims=".
Just out of habit, when reading the contents of a file with a for /f loop, I find it useful to enable usebackq just in case the filename / path contains a space or ampersand. That allows you to quote the filename to protect against such potential treachery.
#echo off
setlocal
for /F "usebackq skip=1 delims=" %%I in ("stats.txt") do if not defined URL set "URL=%%~I"
echo %URL%
Put into context, to use this to read many files named stats.txt and output the URLs into a single collection, enclose the whole thing in another for loop and enable delayed expansion.
#echo off
setlocal
>URLs.txt (
for /R %%N in ("*stats.txt") do (
for /F "usebackq skip=1 delims=" %%I in ("%%~fN") do (
if not defined URL set "URL=%%~I"
)
setlocal enabledelayedexpansion
echo(!URL!
endlocal
set "URL="
)
)
echo Done. The results are in URLs.txt.
If you want to strip the "URL = " from the beginning of each line and keep only the address, you could try changing your for /F parameters to "usebackq skip=1 tokens=3" if all the files follow the same format of URLSpace=Spacehttp://etc.. If you can't depend on that, or if any of the URLs might contain unencoded spaces, you could also change echo(!URL! to echo(!URL:*http=http!
You don't need to use a FOR /F loop, you can also read it with a SET /P
setlocal EnableDelayedExpansion
< stats.txt (
set /p line1=
set /p URL_Line=
)
echo(!URL_Line!
Try this from the command line:
(for /F "tokens=1* delims=:" %i in ('findstr "URL" stats*.txt') do echo %j) > output.txt
the idea ... is to return the 2nd line with URL
If you want to insert this line in a Batch file, just double the percent signs.
Try this from the prompt:
(for /f "tokens=1*delims=]" %a in ('find /v /n "" *.csv^|findstr /l /b "[2]"') do #echo %b)>u:\r1.txt
Where - I used *.csv for testing (substitute your own filemask) and I used u:\r1.txt for the result - substitute as seems fit (but don't output to a file tat fits your selected filemask !)
It works by prefixing each line in each file with a bracketed number [n] (find - /n=and number /v lines that do not match "" - an empty string); then selecting those lines that /l - literally /b at the beginning of the line match "[2]".
The result is all of the second-lines of the files, preceded by the literal "[2]". All we need to do then is tokenise the result, first token up to delimiter "]" will be "[2" assgned to %%a and remainder-of line (token *) will be assigned to %%b
Have you tried
for /F "skip=1 tokens=1 delims=\n" %i in (stats.txt) do echo %i && goto :eof
I haven't tested it as I don't have access to a Windows machine at the moment, but that should exit the for-loop after the first iteration, which is what you want.
First thank you for this great site! I've learned lots of batch scripting from here, but finally got stuck. I was tasked to write a script that will go out and check a specific registry keyword and change the ones that are not correct, on all PCs on the network.
#echo off
SetLocal EnableDelayedExpansion
FOR /F %%a in (C:\batchFiles\computers.txt) DO (
FOR /F "tokens=3" %%b in (reg query "\\%%a\HKLM\SOFTWARE\some\any" /v "Forms Path") do set "var=%%b"
if "%var%" == "\\server\folder\forms\path"
echo %%a was correct
pause
if "%var%" NEQ "\\server\folder\forms\path"
echo %%a was not correct
pause
)
My boss tasked me with this not to long ago and its a little above my head, so i'm trying to learn on the fly. I tried with %errorlevel% and couldn't get it to do what I wanted either.
I had all of my PC names listed in C:\batchFiles\computers.txt. The REG_SZ key from "Forms Path" is a folder located on a network drive. Right now it says that the syntax is incorrect.
If you can understand what i'm trying to do, and have a better suggestion, I'm all ears! Oh and I'd like to output ALL of the results to a text file so I know which PCs were changed, which ones had it correct, and which ones the script couldn't reach.
Thank you so much for your time!
You enabled delayed environment variable expansion, but do not use it. %var% must be written as !var! to make use of delayed expansion as required here.
The syntax used on both if conditions is also not correct.
The registry query output by reg.exe on my computer running Windows XP is:
! REG.EXE VERSION 3.0
HKEY_LOCAL_MACHINE\SOFTWARE\some\any
Forms Path REG_SZ \\server\folder\forms\path
There is first a blank line, next a line with version of reg.exe, one more blank line, a line with registry key and finally on fifth line the data of interest. Therefore I used in the batch code below skip=4 to speed it up. However, the inner loop would produce the right result also without skip=4 and therefore parsing all 5 lines.
Important is the last line. The inner loop separates by spaces. As the name of the registry value contains also a space character, the first two tokens are for Forms and Path. And the third token is REG_SZ.
The rest of the line after the spaces after REG_SZ is of real interest, but could contain also a space character. So I used in batch code below not tokens=4, but instead tokens=3* and ignored %b which holds REG_SZ. Instead %c is assigned to environment variable var resulting in getting really entire string value even if the string contains 1 or more spaces.
And the environment variable var is deleted before a new query on next computer is executed in case of a computer does not contain the registry value at all. The error message written by reg.exe to stderr is redirected to device nul for this case. The value of var would be unchanged from previous computer if not deleted before running the next query.
#echo off
setlocal EnableDelayedExpansion
for /F %%a in (C:\batchFiles\computers.txt) do (
set var=
for /F "skip=4 tokens=3*" %%b in ('%SystemRoot%\System32\reg.exe query "\\%%a\HKLM\SOFTWARE\some\any" /v "Forms Path" 2^>nul') do set "var=%%c"
if "!var!" == "\\server\folder\forms\path" (
echo %%a has correct value.
) else if "!var!" == "" (
echo %%a does not have the value at all.
) else (
echo %%a has wrong value.
)
pause
)
endlocal