If I had a text file that was a list of things in the following format:
Thing1 "Description of Thing1"
Thing2 "Description of Thing2"
etc.
How would I use a batch file to echo only the information contained in the quotes for any given thing?
Edit: Per the answer, I've tried the following:
for /f "tokens=1*" %%a in (G:\Games\Console\Emulators\MAME\listfull.txt) do if "%%a"=="%%~nf" set gamename=%%~b
echo !gamename!
if !count!==1 echo|set /P=", "!gamename!": [#name: "%%~nf", #path: "%%~dpf"]" >> "G:\Games\Console\Utilities\Lists\MAME_%%d.txt"
It almost totally works; if the description contains an &, symbol, however, "echo !gamename!" works while the next line doesn't and spits out that "&' isn't a command. (I have to use the echo|set to produce lines that don't have a carriage return.)
Edit2: The only solution I've found is to add an ^ before every & in whatever text file I'm reading the descriptions from. Not an ideal workaround, but...
set "search=Thing2"
for /f "tokens=1*" %%a in (textfile.txt) do if "%%a"=="%search%" echo %%~b
If all this script does is outputs the information for any given thing, then you could change search to %~1 and just input the value when calling the script.
for /f "tokens=1*" %%a in (textfile.txt) do if "%%a"=="%~1" echo %%~b
for /f "tokens=1*" %%a in (file.txt) do echo(%%~b
Related
Ok so I'm super close to doing what I need to do.
I'm having an issue with my rename command and a double letter at the end of the folder. The folder names in the code have been changed for privacy, Spaces have been kept to show how the folders would be named.
The double letter is uppercase I (eye), this can't be changed.
Yes this file exists.
Example:
FolderII - error: The system cannot find the path specified.
Folder - Works
FolderI - works
for /r "C:\Folder Name" %%a in (*) do if "%%~nxa"=="FileFound" set p=%%~dpnxa
for /f "usebackq tokens=1* delims=." %%A in ("%p%") do set Build=%%B
for /f "tokens=2 delims==" %%G in ('wmic os get localdatetime /value') do set datetime=%%G
for /f "tokens=3 delims=\" %%Z in ("%p%") do set filepath=%%Z
set year=%datetime:~0,4%
set month=%datetime:~4,2%
set day=%datetime:~6,2%
set dbname=Logdb%year%.%Build%
REN "C:\Folder Name\%filepath%\%dbname%" "Logdb%month%-%day%-%year%.%Build%"
OUTPUT
EDITED!
CMD>REN "C:\Folder Name\FolderII\Logdb2020.ext" "Logdb11-23-2020.ext"
The system cannot find the file specified.
Added
CMD>REN "C:\Folder Name\Folder\Logdb2020.ext" "Logdb11-23-2020.ext"
THIS works
EDIT FOR CLARIFICATION*
I'll explain this how I intended it to work, which it does as long as the folder it's being assigned to doesn't have a II in it.
1st line: Search this particular folder for a file called "SYSCON" no extension, once found assign to p the file path of the file for 2nd line
2nd line:Open file found at 1st line and get the extension of the file listed inside the file and assign it to Build
3rd line:Get the current date to assign to the new file name in REN
4th line:Use the file path found in line 1 to get the folder name for the REN
5-7 set date variables
Line 8:Assign the new file name to variable
Line 9:Rename the old file at the location found to the new file name generated
I'm not a batch developer, I've literally written these lines as they work for me, but I'm always willing to learn how to do better, I'm a PHP programmer. This is a different project.
The folder structure is fluid for the application. The reason for the search for the initial file is to find the file in 1 of 4 folders and then get that actual folder name.
I can echo all the variables and see the correct file path, the correct file name and the correct new file name.
When it comes to rename the file in the folder with II, it fails to find the actual file to do the rename on, that's where I'm stuck.
IMAGE of Output echoed as it steps through the lines, for privacy sake I have to change the file names. Here's the CMD output for, I hope, better understanding
I'm not positive, based upon your lack of specific information, but as a best guess, I'd assume that something like this should perform the task, I think your example is trying to achieve.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Tokens=1-3 Delims=/ " %%G In (
'""%__AppDir__%Robocopy.exe" \: . /NJH /L | "%__AppDir__%find.exe" " 123""'
) Do Set "YYYY=%%G" & Set "MM=%%H" & Set "DD=%%I"
For /D %%G In (C:\Folder Name\*) Do For %%H In ("%%G\SYSCON"
) Do If "%%~aH" Lss "d" If "%%~aH" GEq "-" (
For /F "UseBackQ Tokens=1,* Delims=." %%I In ("%%H") Do Set "Build=%%J"
SetLocal EnableDelayedExpansion
Ren "%%G\Logdb%YYYY%.!Build!" "Logdb%MM%-%DD%-%YYYY%.!Build!"
EndLocal)
The example above expects the the string you're using for the Build variable is on the last non empty line of the target file, (ASCII text with CRLF line endings). If it is the only non empty line in that target file, then perhaps the following would be more useful:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Tokens=1-3 Delims=/ " %%G In (
'""%__AppDir__%Robocopy.exe" \: . /NJH /L | "%__AppDir__%find.exe" " 123""'
) Do Set "YYYY=%%G" & Set "MM=%%H" & Set "DD=%%I"
For /D %%G In (C:\Folder Name\*) Do For %%H In ("%%G\SYSCON"
) Do If "%%~aH" Lss "d" If "%%~aH" GEq "-" (
For /F "UseBackQ Tokens=1,* Delims=." %%I In ("%%H"
) Do Ren "%%G\Logdb%YYYY%.%%J" "Logdb%MM%-%DD%-%YYYY%.%%J")
It would seem that the data assigned to build contains trailing spaces and perhaps some invisible characters. The easy way would be to simply change 1* to 1,2.
Since Space is a default delimiter, %%B will be assigned the value between the first and second spaces on the line. Tough if you want spaces in the extension, but do you really want to use extensions with spaces?
The syntax SET "var=value" (where value may be empty; in which case var becomes undefined) is used to ensure that any stray trailing spaces are NOT included in the value assigned.
I have txt files that contain several lines and I need to create a log out of them to store in a log the following information:
File Name
Last modified
Count of lines containing the word "valid"
I've put together a .bat file but it splits the output in two lines.
type nul > FilesReceived.txt & for %f in (*.log) do (
find /c "valid" %f & echo(%~tf)>> LogsReceived.txt
)
With type nul I clear the contents of the FilesReceived.txt file. Then I loop through the files of type log.
Then I count lines that contain the word valid with find /c and I also echo the last modified time stamp.
However the output looks like:
---------- transaction_20160505_1005A.log: 6492
10/06/2016 04:37 p.m.
I don't know what's generating those dashes. Ultimately I'd like to have one line per log file as follows:
transaction_20012B.log: 6492 10/06/2016 04:37 p.m.
Hope you guys can help me.
Thanks,
Bruce
find prints the dashes if it processes a file. It doesn't, when processing from STDIN (type file.ext /c |find "string" prints the count only).
There is a trick to write without linefeed: <nul set /p"=Hello"
If you can live with another order, it's quite easy to assemble it::
#echo off
for %%f in (*.bat) do (
<nul set /p "=%%f %%~tf "
type %%f|find /c "echo"
)
If you want to keep your order it's a little bit more complicated: you can't force find to write without linefeed, so you have to use a trick (another for):
#echo off
(for %%f in (*.txt) do (
<nul set /p "=%%f: "
for /f %%i in ('type %%f^|find /c "valid"') do (<nul set /p "=%%i ")
echo %%~tf
))>LogsReceived.txt
You may get the output of find command via another for and put it at any place you wish:
#echo off
(for %%f in (*.log) do (
for /F %%c in ('find /c "valid" ^< %%f') do echo %%f: %%c %%~tf
)) > LogsReceived.txt
I am trying to find the following version number in a app.config file.
The file is XML format.
Line 8 in the file (Adding line in again as the greater/less than symbols were stripped from the post initially)
add key="ReleaseVersion" value="5.2.0.2"
I been using various FOR /F commands, have been close a couple of times.
However I have not been able to extract the 5.2.0.2 value and use as a variable
so far in my script.
Additionally while I am looking for this value 5.2.0.2, going forward the version number will change so I am not looking for a exact match e.g. "5.2.0.2", I am looking to capture what is in the inverted commas e.g. value="", and then using this as a variable in my script.
Example of what I have tried so far...
FOR /f "tokens=3 delims=5." %%a IN ('TYPE appsettings.config ^| FIND "ReleaseVersion"') DO SET do set word3=%%a
FOR /F delims^=^"^ tokens^=2 %%G IN ('FINDSTR /L "ReleaseVersion" "appsettings.config"')
FOR /f "tokens=3 usebackq delims== " %%G in (`appsettings.config`) do #echo %~G
Have tried a number of techniques but as yet, nothing has been successful.
Can post more information as required however that essentially covers the issue.
Supposing the add key="ReleaseVersion" value="5.2.0.2" portion is in a single line and the related value parameter appears after the ReleaseVersion substring, the following could work for you:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem define constants:
set "SEARCH=ReleaseVersion"
set "KEYWORD=value"
rem get line of interest and assign it to `LINE`:
for /F "delims=" %%L in ('findstr /L "%SEARCH%" "app.config"') do (
set "LINE=%%L"
)
setlocal EnableDelayedExpansion
rem cut everything off up to the search string:
set "LINE=!LINE:*%SEARCH%=!"
rem cut everything off up to the keyword:
set "LINE=!LINE:*%KEYWORD%=!"
rem extract the version number:
for /F tokens^=1^ delims^=^"^=^/^<^>^ %%N in ("!LINE!") do (
set "VNUM=%%N"
)
rem transfer the version number over the `setlocal`/`endlocal` barrier:
endlocal & endlocal & set "VNUM=%VNUM%"
echo ReleaseVersion: %VNUM%
exit /B
The string portion of interest does not need to look exactly like shown above, but may contain more or less spaces (for example add key = "ReleaseVersion" value = "5.2.0.2"), or include the " or not (like add key=ReleaseVersion value=5.2.0.2). The only condition is that the attribute key needs to appear before the attribute value.
If the search line is precisely this one:
add key="ReleaseVersion" value="5.2.0.2"
... then this code should work:
#echo off
setlocal
for /F "tokens=3" %%a in ('findstr "ReleaseVersion" "appsettings.config"') do set %%a
set "value=%value:~1,-1%"
echo %value%
If the layout of the search line change (more blank spaces or other characters, less quotes, etc) then previous code should need an adjustment.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q34445384.txt"
FOR /f "tokens=3delims==" %%a IN (
'findstr /L /c:"add key=\"ReleaseVersion\" value=" "%filename1%"') DO SET "release=%%~a"
ECHO release=%release%
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q34445384.txt containing your data for my testing.
Simply find the target string using findstr and set the environment variable to the third token using delimiters of =, removing the quotes from the value with ~.
This assumes uniqueness of the target text and that the structure of the line is exactly as posted.
Assuming app.config is valid, well-formed XML, the best way to scrape the release version is to query it via XPath. You can invoke PowerShell for this.
#echo off
setlocal
set "psCommand=powershell "^
select-xml \"//add[#key^='ReleaseVersion']\" app.config ^| %%{ $_.node.value };^
""
for /f %%I in ('%psCommand%') do set "version=%%~I"
echo %version%
This will parse app.config for a node named "add" which has an attribute named "key" whose value is "ReleaseVersion", then will return that node's "value" attribute's value. for /f captures it to a batch variable.
I have a utility (myexefile.exe) which outputs a list of information like this:
Line1=[Information in line1]
Line2=[Information in line2]
Line3=[Information in line3]
Line4=[Information in line4]
, etc.
I use a .bat file to write this information to a text file like this:
set myexefile="c:\myexefile.exe"
set outputfile="c:\outputfile.txt"
%myexefile% >> %outputfile%
However, I would like to write all of the lines except for the line containing "Line3=".
So I want the output to the outputfile.txt to be:
Line1=[Information in line1]
Line2=[Information in line2]
Line4=[Information in line4]
, etc.
I could probably create the file as it is and then use an existing sample which shows how to remove a line from a text file, but I would rather skip the line in the first place, rather than writing it to a text file and then removing it.
Can someone help me with this?
%myexefile% | find /v "Product ID">> %outputfile%
should filter out any line containing Product ID
setLocal enableDelayedExpansion
set outputfile="c:\outputfile.txt"
for /f "delims=" %%a in ('c:\myexefile.exe') do (
set out=%%a
if "!out:~0,4!" NEQ "Line3" echo %%a>>%outputfile%
)
or alternatively -
set outputfile="c:\outputfile.txt"
for /f "delims=" %%a in ('c:\myexefile.exe') do for /f %%b "delims=:" in ("%%a") do if "%%b" NEQ "Line3" echo %%a>>%outputfile%
I'm trying to use WMIC to remove some old printers on our older print servers
if I use the below syntax from the command line it works
WMIC PRINTER WHERE "SERVERNAME LIKE '%%OLDSERVERNAME%%'" DELETE
I was asked to see if I could make it replace the printers or update them to spare the helpdesk from getting "how do I add my printer" calls
I tried some variation with SET to set the properties for SERVERNAME, it appear to process, but nothing changes and doing a GET shows the old value still.
so I figured I could do a FOR /F loop, wrap the name of the printer (sharename) in a variable and then use another command to recreate the printers, after the offending printers have been deleted.
here's my script
#ECHO
ECHO Gathering Installed Printer Information...
FOR /F "tokens=1 skip=1" %%A IN ('WMIC PRINTER WHERE "Servername like "%%printaz1%%"" get sharename') DO SET PRINTERNAME=%%A
ECHO %PRINTERNAME%
so you would think you'd get the value all wrapped up in a nice variable to do with as you wish but no, I turned echo on and it appears that the variable gets set back to null as soon as it's captured
my output looks like this...
FOR /F "tokens=1 skip=1" %%A IN ('WMIC PRINTER WHERE "Servername like "%%printaz1%%"" get sharename') DO SET PRINTERNAME=%%A
SET PRINTERNAME=nameofprinter
SET PRINTERNAME=
ECHO
ECHO is on.
would love some thoughts on why it seems to be dumping the string.
Powershell and VBScript aren't out of the option either, I'm familar with both, just this seemed possible, and I really don't want to start over.
WMIC is returning two lines, one with the printername, and one empty.
The solution to this is to test for empty lines.
ECHO Gathering Installed Printer Information...
FOR /F "tokens=1 skip=1" %%A IN ('WMIC PRINTER WHERE "Servername like "%%printaz1%%"" get sharename') DO if not "%%A"=="" SET PRINTERNAME=%%A
ECHO %PRINTERNAME%
what you are looking for is this:
for /f "skip=2 tokens=2 delims=," %%A in ('WMIC PRINTER WHERE "Servername like "%%printaz1%%"" get sharename /format:csv') DO SET PRINTERNAME=%%A
ECHO %PRINTERNAME%
Explanation:
The unicode output of wmic includes a carriage return which is captured by the FOR /F which is what you do not want, as it means the 'enter' becomes part of your variable (%%A) and it also contains an empty line, which again will be outputted to %%A.
My example does the following:
/format:cvs -- will output a comma seperated output so we can capture using the delimiter ,
skip=2 -- will skip the empty line at the beginning and skip the header row of the csv.
tokens=2 -- the csv output contains the name,value as output, but you only want value, which is the second token.
by the way, because we no longer include space as a seperate it should even work with spaces in the value. give it a try.
I got around the UNICODE carriage return (which is really the problem here) like this:
#echo off
FOR /F "usebackq tokens=1,2 delims==" %%A IN (`wmic %* /VALUE ^| findstr "="`) DO (call :OUTPUT %%A "%%B")
exit /b
:OUTPUT
echo %1=%2
Save that as "wmi.bat"
and execute your query like this:
wmi.bat printer where 'name like "HP%"' get name
My output looks like this:
Name="HP1C0BCA (HP Officejet Pro 276dw MFP)"
Name="HP Officejet Pro L7500 Series"
Name="HP Officejet Pro 276dw MFP PCL 6"
You can imagine how you can play with this.
the "%%B" portion puts all of the output of /VALUE (including spaces) into the %2
%%A captures the object id, which becomes %1 which is handy if you use this to log all sorts of information from WMI. You don't have to worry about the Unicode carriage return anymore.
The big advantage of this approach is that you have a clever batch file which overcomes the limitations that wmic gives you when using it inside a script, and you can use it for anything.
you can use the STDOUT of the batch file as the parameter for anything else, even as input to wmic!
The most secure and general variant is to nest another for /F loop, like this:
for /F "skip=1 usebackq delims=" %%A in (`
wmic Printer where 'Servername like "%%printaz1%%"' get ShareName
`) do for /F "delims=" %%B in ("%%A") do set "PRINTERNAME=%%A"
The problem is the Unicode output of the wmic command and the poor conversion to ANSI text by for /F, which leaves some orphaned carriage-return characters, which in turn lets appear some additional lines as non-empty. The second for /F loop gets rid of these conversion artefacts.
I also replaced the tokens=1 option by delims= in order not to truncate the returned item at the first white-space.
Take also a look at the following related answers by user dbenham:
Why is the FOR /f loop in this batch script evaluating a blank line?
For /F with wmic unwanted output
#ECHO
ECHO Gathering Installed Printer Information...
FOR /F "tokens=1 skip=1" %%A IN ('WMIC PRINTER WHERE "Servername like "%%printaz1%%"" get sharename') DO (
SET PRINTERNAME=%%A
goto end
)
:end
ECHO %PRINTERNAME%