Output from FINDSTR into a string in batch command - batch-file

I would be really grateful for anyone that could save me some time on this.
I have a Windows batch file that I am using to match two different file types with different extensions and write the results out to a file.
It reads through a table of filenames (called matched_filenames.txt) and, for each line in it, tries to locate the filename in two other tables.
I have this code (which works to an extent).
for /f "tokens=*" %%z in (%Ourhome%\matched_filenames.txt) do (
rem -------
rem ------- now (for each line), find the photo name in both the list of raw and list of jpg files
rem -------
findstr /C:"%%z" raw_photos_directory.txt >>located_matches.txt
findstr /C:"%%z" jpg_photos_directory.txt >>located_matches.txt
)
But it writes separate lines out to the located_matches.txt file.
I would really like to assign the results of the findstr's to variables so that I can then concatenate them and then write the concatenated line as a single line to the file.
Can anyone recommend a more elegant way of doing this?

Related

Batch extracting specific file types from master directory with many subdirectories

I have a quantity of folders with archive files,
Parent folder with subfolder eg
Graphics:
graphics 01012021/file31241.7z
graphics 01022021/file4231.7z
odds and ends 01032022/filejohnny.7z
etc
each folder contains an archive - various names numbers.
each archives contains various files, pdf's txt files invoices and image files.
Generally the images are .jpg named various names.
What I would like to do is batch attack the parent folder to extract an image file/s from the each archive from each sub directory and leave the image in the subdirectory with the archive where it came from. If the archive has multiple images that's fine, I am not targeting a single particular image.
hopefully ending up with something like
Graphics:
graphics 01012021/
file31241.7z
yellowstone.jpg
flintstone.jpg
graphics 01022021/
file4231.7z
martha.jpg
odds and ends 01032022/
filejohnny.7z
artemis.jpg
French toast.png
I would rather avoid if possible extracting all the files separating the images then having to re archive.
What I tried to discover originally was to batch extract the image files to the directory it belongs to, have the image file renamed to its directory name. I didn't get close with a solution, so I think if possible just extracting the image would be fine and I can use a renaming app to do the other I've found bulk rename utility to be just fine once I got my head around it.
You wouldn't think that over the years you would collect so many archives, like small drops they ended up become an ocean full.
I have tried researching stack and seen a lot of examples of how eg 7zip works but I just cant get my head quite around it.
I am due to retire they tell me 65 is the time for the chicken coop, I've been a pencil pusher and mouse skater most of my life in the gfx industry. I used to know what was in each archive but memory is a little how to say... rusty nowadays, I know all my archives have images in them. My life would be a lot easier in the sunset of it to look at the pictures and not have to rack my brains trying to remember what was in the archive itself.
Cheers and ty in advance from the colonies downunder.
Grumpy
I found the solution to my issue, no coding just using an app I've been using for years. Total Commander.
Solution was simple in the end.
I open up Total Commander, do a search for the archive files I want Alt F7 it will list in the right hand frame all my archives .7z .zip whatever you have.
Then you select "feed to list box" found in the bottom right hand corner. Do a Ctrl A then Alt F9 which gives you some options.
You clear unpack specific files from archive to "make sure its blank" then files to unpack tell it what your looking for in my case .jpg (it can be any specific file).
Untick unpack path names if stored with files
tick or untick overwrite existing files
untick unpack each archive to a separate subdir (name of the archive)
Hit ok.
It will then search and find the file/s you are looking for and unpack them in the directory/subdirectory/etc they are found in.
Job done... No coding just using TC.. marvellous app
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
SET "outfile=%destdir%\outfile.txt"
SET "extensions=bat txt"
SET "archives=7z zip"
CALL :prefix sdexts *. %extensions%
CALL :prefix sdarchives *. %archives%
CALL :prefix dexts . %extensions%
CALL :prefix darchives . %archives%
PUSHD "%sourcedir%"
(
FOR /f "delims=" %%b IN ('dir /b /s /a-d %sdexts% %sdarchives%') DO (
SET "unreported=%%b"
FOR %%o IN (%darchives%) DO IF /i "%%~xb"=="%%o" CALL :procarch%%o&SET "unreported="
IF DEFINED unreported ECHO %%~dpb ^| %%~nxb
)
)>"%outfile%"
popd
GOTO :EOF
:: return %1 with each other argument preceded by '%2'
:prefix
SET "$1=%1="
shift
SET "$2=%~1"
:sdl
SHIFT
IF "%1"=="" SET "%$1%"&GOTO :eof
SET "$1=%$1% %$2%%1"
GOTO sdl
:: Process .7z or .zip archives
:procarch.7z
:procarch.zip
SET "skipme=Y"
FOR /f "delims=" %%e IN ('7z L "%unreported%"') DO (
FOR /f "tokens=3delims= " %%o IN ("%%e") DO (
IF "%%o"=="------------" (
IF DEFINED skipme (SET "skipme=") ELSE (SET "skipme=Y")
) ELSE IF NOT DEFINED skipme ECHO "%%o"|FIND "D" >NUL &IF ERRORLEVEL 1 (
SET "filename=%%e"
FOR /f "delims=" %%y IN ("!filename:~53!") DO (
FOR %%c IN (%dexts%) DO IF /i "%%c"=="%%~xy" ECHO %unreported% ^| %%y
)
)
)
)
GOTO :eof
I've a similar requirement, so I spent a bit of time on this...
The first part simply sets the directories to be used.
I used bat and txt as extensions required for testing. Change as desired - just a space-separated list.
Similarly, I chose to examine .zip and .7z archives. Since 7zip can deal with both, the same subroutine can be used to process both. Other archive types may need different processing.
The code uses dir to locate the files of interest, and dir can take a series of arguments, so the routine :prefix converts the list provided as %3+ to a list in variable %1, each term prefixed by the string at %2.
So - sdexts will become *.bat *.txt and dexts .bat .txt for instance.
Next, switch to the source dir to begin the dir to list the required files. For each name returned in %%b (delims= applies the full name, /b basic list (names only), /s processes subdirectories, /a-d suppresses directorynames) - the flag unreported is set to the filename found then the extension of the filename found is compared to the darchives list. If a match is found, execute the procarch%%o routine is executed and the unreported flag set to empty. Then, if unreported has not been cleared, it's not an archive file, so report it.
procarch%%o will be resolved either procarch.7z or procarch.zip and a routine (actually the same routine) is provided.
The :prefix routine sets $1 to %1=, so for example, sdexts=. Then it shifts the parameter list and sets $2 to the prefix to be placed before each term.
Then shift again. If %1 is not empty, append a space and the prefix in $2 and %1 to $1 and repeat.
When %1 becomes empty, execute the command set "%$1%" and finish, so as $1would then contain the stringsdexts= *.bat *.txt, sdexts` would be set to the list required.
The routine :procarch.7z or procarch.zip (the first simply falls through to the second, so the same processing is executed) sets the flag skipme to non-empty as we need to skip 7z's header data.
%%e acquires each line of the 7z L report in turn. %%o is assigned the third token of the 7z report line. This will be junk up to the line with a series of dashes, then the attribute report for the archived items, then another series of dashes, then junk.
So - if %%o is a string of dashes, simply switch skipme to empty/not empty.
If %%o is not dashes, and skipme is not defined then we are between the two lines of dashes (ie. on an archived item line) so we see whether %%o contains D (which would indicate that this is a directory name, which we do not want to report). If it does not, errorlevel will be set non-zero by the find (output of the find is sent to nul=the æther) filename set to the full report line. We're not interested in the first 54 characters, but the remainder contains the archived filename, so see whether the extension of the filename found is one of interest (in dexts) and if it is, report it.
The ( on the line preceding the for ... %%b matches the )>"%outfile%" and sends all output that would otherwise go to the console to the file named.
And the ^| on the echo lines output a literal | character as | is a special character for cmd and needs to be escaped by ^ to be interpreted as a literal.
To answer your question the task is simple involving For loops with recursion, however to be robust the solution will be complex without knowing how those specific long term possibly mixed, 7zip files are subdivided, thus if a 7zip has itself two sub folders with identical named files you will hit error conditions. I have allowed for that using -aou to auto rename if necessary. however I have not added the folder name to each file as that's an extra step.
#echo off & Title Extract Images from 7z files
set "extractor=C:\Program Files (x86)\7-Zip\7z.exe"
set "archives=*.7z"
set "filetypes=*.png *.jpg *.jpeg *.tif *.tiff"
set "startDir=C:\Users\WDAGUtilityAccount\Desktop"
FOR /R "%startdir%" %%I IN (%archives%) DO ( "%extractor%" e "%%I" -o"%%~dpI" %filetypes% -aou)
You can add extra archive types such as .rar or .zip in the same way I have allowed for different image file types. HOWEVER do test for such variations first otherwise a second run will invoke that autonaming of existing duplicates. You can of course change that -aou to -aos to avoid overwite or remove it as desired.
An alternative approach on windows is that, standard windows.zip files can be navigated and thus kept as compressed folders where a click on each file will open in the default application. Thus only need extraction to the folder when you wish to use a non default app.
The secondary advantage more directly related to your need is that some viewers can read just the images and ignore any other contents (even if they can read text or html) and one I support that reads images in zips is SumatraPDF and although not listed it can open .7Z files to show in the same way
Hence my answer to the posed question is I suggest converting 7zip to standard zip rather than expand them, or use SumatraPDF as default/alternative 7z viewer !!.

How do I remove only certain words (not lines containing that word) from a text file with a Batch?

I'm writing a batch file that uses an output from a dir command to perform other tasks, I also want to use this same output (stored in dir_output.txt) for another use, but I don't want the file extensions at the end. right now the file looks like this:
barrier_1_post.p3d
barrier_1_section.p3d
but I want it to look like this
barrier_1_post
barrier_1_section
minus the file extensions, but I have no idea how to do this via the batch, I've looked through SO exhaustively but either I'm not finding the solution or I can't see the wood for the trees.
Any help would be amazing, I'm fairly new to batches.
for /f "delims=" %%a in (yourfilename.txt) do echo %%~na
should remove those extensions quite happily.
%~na delivers the name part only of the assumed filename in %a
(see for /? from the prompt for documentation)

Extract specific text from text file using batch

I'm trying to extract specific text from a text file using batch code. The file from which I need to extract data will have multiple lines of text and the number of lines will vary, which means the position of the indicators will change as well. Here's a sample of the text file:
File 1:
<File>
<General>
<Primary_1>1.2.3.4.5</Primary_1>
<Secondary_2>9.8.7.6.5</Secondary_2>
</General>
<Main_List>
<Details="Title" One="C:\Folder1\Folder2\Folder3\Folder4\Folder5" Two="I" Three="4"/>
</Main_List>
</File>
I've gone through some manipulation already and extracted the lines that contain the data I need from the text file and saved it to two separate text files so I end up with this:
File 2:
<Primary_1>1.2.3.4.5</Primary_1>
File 3:
<Details="Title" One="C:\folder1\folder2\folder3\folder4" Two="A" Three="5"/>
So, from the two files above (file 2 & file 3), I need to be able to extract two values. The first being between the |Primary_1| and |/Primary_1| indicators...in this case I would need to pull the "1.2.3.4.5" value. The second being the value after the |Details="| and before the |" One=| indicators...in this case I would need to pull the "Title" value.
I searched around and couldn't find anything that quite fit the bill. The closest I found was the "...on the same line..." code (Extract part of a text file using batch dos), but I kept getting errors. Any help would be greatly appreciated. Thank you.
Try this when both lines are in file.txt
It works for the txt as given, if TABs aren't in the file.
#echo off
for /f "tokens=2 delims=<> " %%a in ('find "<Primary_1>" ^< "file.txt" ') do echo "%%a"
for /f "tokens=2 delims==" %%a in ('find "<Details =" ^< "file.txt" ') do SET "xtitle=%%a"
SET ntitle=%xtitle:~1%
SET xtitle="%xtitle%"
ECHO +%ntitle%+ or +%xtitle%+ - your choice...
There is a more robust method using a helper batch file if your wanted text contains spaces.
(little tickle by Magoo - allows spaces in the quoted "Title" string - but I don't know whether the requirement is for quoted or unquoted variable contents...so you get both. (no extra charge)

Use Dos commands to copy file and preserve date in file name

I'm having trouble trying to copy and rename a file using only dos commands. I have a file of the format myfile20130218 and want to copy and rename it to some_other_file_20130218.
I know I can use copy source dest but I'm having trouble with how to isolate the date and preserve it. I cannot guarantee that he date will be today's date so that is ruled out, the source file will always be the same name.
I can run either a series of commands or a batch script, but thing that that I am currently having trouble with, is after I find a match that I need to copy, using myfile????????, how can I now get those file names to pull the dates off them?
EDIT: for clarification I will be looking at files in a known directory, as above, I will know the format of the file name, and will only be checking a specific directory for it. The process that checks the directory is a ConnectDirect file watcher, so when a file is found matching myfile20130218 I can fire off some commands, but don't know how to check the directory and get the name of the file present.
Something like this should work:
%oldname:~-8% extracts the last 8 characters from %oldname% which are then appended to the new filename.
Update: If you can identify the file with an external program and then call the batch script with the file name
copyfile.cmd C:\path\to\myfile20130218
you could do something like this:
set oldname=%~nx1
set newname=%~dp1some_other_file_%oldname:~-8%
copy "%~f1" "%newname%"
Update 2: If you know folder and the format you could call the script with the folder
copyfile.cmd C:\folder
and do something like this:
#echo off
setlocal EnableDelayedExpansion
for /f %%f in (
'dir /b "%~f1" ^| findstr /r "myfile[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$"'
) do (
set oldname=%~f1\%%f
set newname=%~f1\my_other_name_!oldname:~-8!
copy "!oldname!" "!newname!"
)
endlocal
Edit: Script breakdown.
setlocal EnableDelayedExpansion enables variable expansion inside loops and conditionals.
for /f %%f in ('...') executes the command between the single quotes and then loops over the output of that command.
dir /b "%~f1" lists the content of the given directory (%~f1 expands to the full path of the first argument passed to the script) in simple mode (no header, no summary).
findstr /r "myfile[0-9]...[0-9]$" filters the input for strings that end with the substring "myfile" followed by 8 digits. The circumflex before the pipe (^|) escapes the pipe, because otherwise it would take precedence over the for command, which would effectively split the for command in half, resulting in an invalid command-line.
set oldname=%~f1\%%f assign the full path to a matching file to the variable oldname.
set newname=%~f1\my_other_name_!oldname:~-8! assign the full path to the new filename ("my_other_name_" followed by the trailing 8 digits from oldname) to the variable newname.
copy "!oldname!" "!newname!" I don't need to explain this, do I?

Combining multiple text files into one

I have searched the world wide web high and low, and can't seem to find any solution for my problem! I have multiple text files that I would like to combine.
It's easier to show examples than to explain exactly why I'm trying to do.
The first file looks like this:
John
Paul
Mark
Sam
Herold
This file serves as a "primary key".
The rest of the files contain data for each item like this. A program generates this data into a new file each hour.
4
10
20
5
200
I'm most familiar with windows batch files, so I tried to write something like this:
for /f "tokens=*" %%A in (file1.txt) do
(for /f "tokens=*" %%B in (file2.txt) do (echo %%A,%%B>>combined.txt))
Unfortunately that writes every value to every person. If this would be working as expected, the end result would be like this:
John,4,2,6,9,1,2,5,6,12,51,53,3,6,7,8,1,4,7,2,743,21,4,7,5
Paul,10,5,6,1,7,9,34,56,1,76,48,23,222,12,54,67,23,652,1,6,71,3,6,4
and so on.
The software I am using presents the data in this format, and cannot be changed. I am open to any and all suggestions.
You may read several input files in a Batch program via the standard handles. Remember that 0 is Stdin, 1 is Stdout and 2 is Stderr, but this leaves handles 3 to 9 available! The Batch file below do a file merge with the contents of two files; of course, up to 8 files can be combined with this method.
#echo off
setlocal EnableDelayedExpansion
Rem First file is read with FOR /F command
Rem Second file is read via standard handle 3
3< file2.txt (for /F "delims=" %%a in (file1.txt) do (
Rem Read next line from file2.txt
set /P line2=<&3
Rem Echo lines of both files
echo %%a,!line2!
))
Further details here: http://www.dostips.com/forum/viewtopic.php?f=3&t=3126
The unix command paste maybe what you're looking for. Also see this question on StackOverflow.
You could just do:
paste -d, file*.txt > combined.txt
if you have paste available. You may need to install cygwin, or work on a *nix machine. (You did say you are open to all suggestions!) This relies on the data files being named sequentially. If you want to tweak the order, you can spell it out instead of using the glob.

Resources