Filename and path extraction - multiple folders - batch-file

I have a set of folders in a drive and need to extract the path and filename of all of the files who have similar names (i.e., index_lms.htm or index*.htm). I need these to go into a csv file, which I will manipulate and use in a mass upload template. Is this possible through cmd shell or a batch file? (It's been a while since I tried writing these.)
Today the size of the task got worse....... I now have 1000 English courses, and translated versions in German, Turkish and Russian. So I really needed a batch solution to extract these pathnames - thank you.
One other issue arose in the the filename cannot have spaces and I see that all of them have multiple spaces in their filenames. Is this easy to edit as the paths/filenames are read?
Quick answer to Gung - the files are loaded into an LMS system and the target file for elearning is normally index.html or index_lms.html or index_html5.html. However the LMS also serves up documents (my current issue) in my case they are all pdf with a standard naming convention

This batch will iterate the given folders and recursively search them for any file beginning with index and create a csv with a header and the columns File, Path and PathFile.
#Echo off
SetLocal EnableExtensions
( Echo "File","Path","PathFile"
For %%A in (
"X:\Test\"
"Y:\Home\Customer\"
"Z:\Users\UserName\"
) Do Call :Search "%%~A"
) > "%~dpn0.csv"
Goto :Eof
:Search
For /R %1 %%B in (index*.htm*) Do Echo "%%~nxB","%%~dpB","%%~fB"
The output file will have the same drive, path and name as the batch file but the extension .csv

This will create file out.csv. Substitute your own dir pattern match.
del 2>nul out.csv
for /f "delims=" %%f in ('dir/s/b c:\index*.htm') do <nul set /p =%%f,>>out.csv

Here is another way to do it in PowerShell.
PS C:\src\t> type .\f2csv.ps1
$dirs = 'C:\src\t', 'C:\labs'
foreach ($dir in $dirs) {
Get-ChildItem -File '*.txt' -Recurse |
Select-Object #{Expression={$_.FullName}; Label="filename"} |
Export-Csv -Path '.\f2csv.csv' -Delimiter ',' -NoTypeInformation
}
PS C:\src\t> .\f2csv.ps1
PS C:\src\t> type .\f2csv.csv
"filename"
"C:\src\t\iosloginfo\lognextnum.txt"
"C:\src\t\t\file1.txt"
"C:\src\t\t\file10.txt"
"C:\src\t\t\file2.txt"

Related

Rename multiple pdf files after reading corresponding text files present in different folder using bat script

PROBLEM
I am working on a bat script which should be able to read 1000 of text files from a location say Z:/Demo/Text and after reading the stored values the script is able to rename the corresponding pdf files present at say Z:/Demo/PDF. The text files are named and read in the following manner: SomeDate_Part1.txt, SomeDate_Part2.txt....
And the PDF files possess the same attribute just the file extension is different.
Renaming logic:
If the value stored in the SomeDate_Part1.txt file is AAA then the corresponding PDF file ie SomeDate_Part1.pdf should be renamed as CGI1_filename.pdf and if the stored value is BBB then it should be renamed as CGI2_filename.pdf.
I wrote a few lines and was able to successfully read all the text files from the folder. The code I wrote is:
#echo off
for %%x in (\Demo\Text\*.txt) do (
for /f "usebackq delims=" %%a in ("%%~fx") do (
if "%%a"=="AAA" echo %%a
if "%%a"=="BBB" echo %%a
)
)
pause
How can I solve the remaining issue?
#echo off
setlocal EnableDelayedExpansion
set "AAA=1"
set "BBB=2"
for %%x in (\Demo\Text\*.txt) do (
for /f "usebackq delims=" %%a in ("%%~Fx") do (
ren "\Demo\PDF\%%~Nx.pdf" "CGI!%%a!_%%~Nx.pdf"
)
)
pause
This code is practically a copy of the original with just two differences:
The values of AAA and BBB are set to 1 and 2, respectively. These values are stated in the question decription.
The two if commands that just display the values in the text files are changed by the desired ren command, as requested in the question description. In the ren command, the location of the .pdf file is set to \Demo\PDF as stated in the question. The new part of the name is comprised by CGI!%%a!_. The %%a contain the value stored in the text file that is AAA or BBB accordingly to the description. In this way, the !%%a! part becomes !AAA! or !BBB! that is replaced by the value of AAA or BBB via delayed expansion, so the new file name is CGI1_SomeDate_Part1.pdf or CGI2_SomeDate_Part2.pdf as requested in the question.
If you are willing to push ahead into PowerShell, this code might do what you want. I have not tested it. When you are confident that the files will be renamed correctly, remove the -WhatIf from the Rename-Item cmdlet.
Save this script as Rename-PdfFiles.ps1.
Get-ChildItem -File -Path '\Demo\Text' -Filter '*.txt' |
ForEach-Object {
$fn = $_.BaseName
$pdfname = "\Demo\Text\$($fn).pdf"
if (Test-Path -Path $pdfname) {
$mark = Get-Content -Path $_
if ($mark -eq 'AAA') { $prefix = 'CGI1' } else { $prefix = 'CGI2' }
Rename-Item -Path $pdfname -NewName "$($prefix)_$(fn).pdf" -WhatIf
}
}
Run it from a cmd shell using:
powershell -NoProfile -File .\Rename-PdfFiles.ps1
If you cannot get past making a .bat file, this might work. I have not tested this either. If it outputs the correct RENAME commands, remove the echo at the beginning of the line.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%x IN ('\Demo\Text\*.txt') DO (
SET "FN=%%~nx"
SET "PDFNAME=\Demo\Text\!FN!.pdf"
IF EXIST "!PDFNAME! (
SET /P "MARK=" <"%%~x"
IF "!MARK!" == "AAA" ( SET "PREFIX=CGI1" ) else ( SET "PREFIX=CGI2" )
echo RENAME "!PDFNAME!" "!PREFIX!_!FN!.pdf"
)

cmd how to delete JPG file and keep only RAW

I´m taking pictures with my mobile phone sometimes in JPG only, but sometimes in RAW. When shooting RAW, mobile phone actually stores two files (filename.jpg and filename.dng).
I would like to write a script which would search defined folder and delete all JPGs which have same filename like the DNGs (RAW).
Example - folder has following files:
IMG_20170625_105228.dng
IMG_20170625_105228.jpg
IMG_20170625_105326.jpg
IMG_20170625_105337.jpg
IMG_20170625_105350.dng
IMG_20170625_105350.jpg
Script should delete:
IMG_20170625_105228.jpg
IMG_20170625_105350.jpg
Iterate over the .dng files and if a like-named .jpg file exists, delete it. When you are satisfied that the correct files would be deleted, remove the ECHO from the DEL command.
PUSHD "C:\the\dir\containing\pics"
FOR /F "usebackq tokens=*" %%f IN (`DIR /B "*.dng"`) DO (
IF EXIST "%%~nf.jpg" (ECHO DEL "%%~nf.jpg")
)
POPD
If, for whatever reason, you wanted to do this in PowerShell, you could do something like this. When the correct files are being removed, remove the -WhatIf from the Remove-Item command. I would be interested to hear from anyone about a better way to do this in PowerShell.
$picdir = 'C:\dir\path\to\pics'
Get-ChildItem -Path $picdir -File -Filter '*.dng' |
Where-Object { Test-Path -Path "$($_.DirectoryName)/$($_.BaseName).jpg" -PathType Leaf } |
Select-Object #{Name="Path";Expression={"$($_.DirectoryName)\$($_.BaseName).jpg"}} |
Remove-Item -WhatIf

How do I write a batch file that moves files to directories where part of the filename matches the folder destination?

I have lots of files that need to go in specific folders. All the filenames have a certain pattern to them and all the folders that need to hold them.
How can I write a batch file with the following rule?
c:\s1_d1111_c1_p1.mpz needs to move to folder c:\SNC1111
c:\s1_d2222_c1_p1.mpz needs to move to folder c:\SNC2222
The filenames always have 4 digits that correspond to the folder. The number after s and c are always 1, and p can have any whole number after it.
This is for Windows Server 2008 R2 Standard
Thanks for your help!
Using Powershell
This sample move the files startin in jdk to a child folder jdk
$files = Get-ChildItem -File
for ($i=0; $i -lt $files.Count; $i++) {
$outfile = $files[$i].Name
if ($outfile.StartsWith("jdk")){
mkdir -Path "jdk" -Force
move $files[$i].FullName "jdk"
}
}
Modify to match your condition and paste the code in a Powershell window
#echo off
setlocal enableextensions
set "source=c:\"
set "targetBase=c:\SNC"
for /d %%f in ("%source%\"
) do for %%a in ("%%~ffs1_d????_c1_p*.mpz"
) do for /f "tokens=2 delims=_d" %%b in ("%%~na"
) do echo move /y "%%~fa" "%targetBase%%%b\%%~nxa"
endlocal
for %%f used to ensure source path will always have an ending backslash
for %%a used to enumerate the files to process from source
for %%b used to split the name in parts and do the move
move command is only echoed to console. If the output is correct, remove echo

Batch: Copy files from txt file into one folder

I am attempting to create a batch file to copy several files listed in a text file to a new folder. I have found several threads relating to this, but I can still not get the batch to work properly. The problem I am encountering is that the files listed in the txt are all in different source locations and have different extensions. The list reads, for example:
C:\Users\Foo\Pictures\Photographs\September\P1030944.jpg
C:\Users\Foo\Videos\Art\Movies\Class\movie.avi
C:\Users\Foo\Music\Jazz\20051.mp3
...etc
All the copy commands I could find have to list either the source directory i.e.
set src_folder=c:\whatever\
set dst_folder=c:\foo
for /f %%i in (File-list.txt) DO xcopy /S/E/U "%src_folder%\%%i" "%dst_folder%"
or the extension i.e.
for /R c:\source %f in (*.xml) do copy "%f" x:\destination\
but I need it to gather that information from the list itself.
If it helps I know that there are only files of a possible 39 different specific extensions in the txt (*.jpg *.gif *.png ... *.xhtml *.xht)
Any help/ideas?
Start reading HELP FOR and then try the following at the command prompt
FOR /F %a in (input.txt) DO #ECHO COPY %a c:\newfolder\%~nxa
you can see that %a gets expanded to the actual line in the input file, and that %~nxa is a way to extract the name and the extension from the file.
After careful testing, move the command to your BAT file, replace %a to%%a, and remove the ECHO command
#echo off
SET destfolder=c:\newfolder
FOR /F "delims=" %%a IN (input.txt) DO COPY "%%a" "%destfolder%\%%~nxa"
notice the wraping of the names with quotes "; and the inclusion of the "delims=" option; both are needed in case filenames contain blanks.
Finally be careful with possible name duplicates in the destination folder. If that is possible, you need to find an strategy to cope with such collisions. But this can be the subject of another SO question, can't it?
One sample which worked for me...
Replace my directories C:\whatever and C:\temp\svn with yours...
assuming that your filelist is named antidump_list.txt and located under C:\temp\svn\
> set src_folder=C:\whatever
> set dst_folder=C:\temp\svn
> for /f %%i in (C:\temp\svn\antidump_list.txt) DO copy "%src_folder%\%%i" "%dst_folder%\%%i"
Regards,
Gottfried
I have found that the easiest way to do this is to use a powershell script.
$Files = Get-Content File-list.txt
$Dest = "C:\output"
foreach ($File in $Files) {
Copy-Item $File $Dest
}
If you need to run it from a batch file, paste the above script to file named CopyFiles.ps1 and add the following command to your batch file
powershell -executionpolicy bypass -file .\CopyFiles.ps1
Since, powershell is included by default on Windows7 and newer, this method is as easy as doing the same with batch commands only.

ROBOCOPY - Copy folders content to a single folder

Here is some code I made :)
#echo off
set source="R:\Contracts\"
set destination="R:\Contracts\Sites\"
ROBOCOPY %source% %destination% *.srt *.pdf *.mp4 *.jpg /COPYALL /R:0 /S
for /r %source in (*) do #copy "%destination" .
R:\Contracts\ is full of folders which have files in them.
I want to copy all to R:\Contracts\Sites\ and flatten the folder structure.
Everything copies well but also the folder structure.
Thank you
You could do that with a PowerShell one liner.
In this example I filter out all the files with the .txt extension from all the subfolders. And then send them to the Copy-Item Cmdlet.
Combine the Cmdlets Get-Childitem (GCI for short), -recurse, and -filter and then pipe the result to the Copy-Item Cmdlet. Use -WhatIf first to check that the output is what you expected.
Copy to another folder (Use -WhatIf and verify the output to check your command before committing to copying the files):
Get-Childitem -recurse R:\Contracts -filter *.txt | Copy-Item -Destination R:\Contracts\Sites -WhatIf
To do multiple filetypes as you've asked, you can just run multiple commands, one for each filetype.
No single command will flatten the hierarchy for you; you will have to use multiple commands. It can be done simply by using FOR /R to walk the hierarchy, coupled with your copy/move command of choice (move, copy, xcopy, robocopy). Because your destination is within the source hierarchy, you need an IF to prevent the destination from being a source.
Before proceeding you should stop and think about what happens if the same file name appears in multiple source folders. You can only have one version in your destination folder. Can you guarantee no duplicate names exist? If not, which file should be kept? How can you structure the command to keep the file you want? This complication is probably why no command was ever written to simply flatten a hierarchy.
Here is your ROBOCOPY command integrated with the FOR /R solution.
#echo off
set source="R:\Contracts"
set destination="R:\Contracts\Sites"
::Not sure if this is needed
::It guarantees you have a canonical path (standard form)
for %%F in (%destination%) do set destination="%%~fF"
for /r %source% %%F in (.) do if "%%~fF" neq %destination% ROBOCOPY "%%F" %destination% *.srt *.pdf *.mp4 *.jpg /COPYALL /R:0
Similar to the previous Powershell option, I did the following to flatten a multi-subdirectory music folder:
#Get all files and not the directories
$files = Get-ChildItem -Path R:\Contracts -Recurse | Where {$_.PSIsContainer -eq $false}
#Copy items from sources to new destination
foreach ($file in $files){
Copy-Item -Path $file.FullName -Destination R:\Contracts\Sites\$($file.Name)
}
The Get-ChildItem with the -Recurse switch will get a listing of all sub-folders and files. The Where function is stripping out any directories by checking the boolean PSIsContainer property. Without stripping the directories the sub-folder structure would be created without files in them. This listing is stored in the $files variable.
The foreach function runs through the list of files in the $files variable and stores one item at a time in the $file variable. The Copy-Item function then uses the full path from $file.FullName and then copies the file to the destination with the same name from $file.Name.
I recently had to tackle this problem, and many files that I wanted to move to from the hierarchy to a single folder had the same name as each other, and I wanted to still flatten the hierarchy without them to being over-written.
What I did was write a script that moves the file, but renames it with the old hierarchy path in the name
for example:
source files:
C:\files\somefiles\file.txt
C:\files\otherfiles\file.txt
destination is C:\newdir\
files are created as
C:\newdir\somefiles-file.txt
C:\newdir\otherfiles-file.txt
here is the code, batch file 1 goes thru the files, batch file 2 renames and moves them (could also copy instead, if you want to preserve the source:
#echo off
for /r %%f in (*.*pr) do #renameandmovefilespart2.bat "%%f" "%%~ff" "%%~xf"
renameandmovefilespart2.bat
#echo off
Setlocal EnableDelayedExpansion
rem set the whole file path
set origWhole=%1
set origPathOnly=%2
set extension=%3
rem here you can set where the directory to hold the flattened hierarchy is
set destDir=c:\destinationDir\
rem set the directory to do a string replace
rem make this the starting directory, that you dont want in the newly renamed files
set startingDir=C:\starting\directory\
set nothing=
set slash=\
rem here you can set what the character to represent the directory indicator \ in the new files
set reaplcementDirectoryCharacter=--
set quote="
rem cut out the starting part of the directory
call set newname=%%origWhole:!startingDir!=!nothing!%%
rem replace slashes with new character
call set newname=%%newname:!slash!=!reaplcementDirectoryCharacter!%%
rem remove quotes
call set newname=%%newname:!quote!=!nothing!%%
rem #echo shortened: %newname%
rem #echo source path: %origPathOnly% newPath: %startingDir%
rem #echo extension: %extension%
rem rename the files
ren %origWhole% %newname%
rem prepare to move the file, clean up the source path
call set origPathOnly=%%origPathOnly:!quote!=!nothing!%%
move "%origPathOnly%%newname%" "%destDir%"
There's an old PCMag utility called Sweep.exe that can operate the same command in the current and subdirectory. I wouldn't put the destination as a subdirectory of the source directory. Put the destination elsewhere.
http://www.rarewares.org/files/case/Sweep.zip
cd c:\contracts
sweep copy *.* c:\sites
This will copy everything from c:\contracts and underneath to c:\sites
I use a similar command to flatten the hierarchy of a directory.
Take care with duplicates and how you want to handle them. Do you want to overwrite or handle a different way.
For those familiar with R copying files to a single folder could be easily scripted as follow. It is more efficient than ROBOCOPY for large sets and directory structures.
## R script - Flatten files in folder structure
# declare your paths
sourcepath<-C:\\Myfolder\\PicturesInStructure"
destpath<-"C:\\Myfolder\\PicturesTogether\\"
# read source filenames with path to vector variable
fileslist<-list.files(sourcepath,
pattern="*.jpg", # in this example copies JPG pictures
full.names=TRUE, # retrieves full path
recursive=TRUE, # runs through all subdirs
include.dirs=FALSE) # skips dir names (no to be copied)
# here you will get a head of your list
head(fileslist)
# ordinary loop by source filenames
for (i in 1:length(fileslist)) {
# Number of Slashes required to extract filename from the source path
NoS<-lengths(regmatches(fileslist[i], gregexpr("/", fileslist[i])))
# for lengthy processes it is good to know where you are with this
cat(i,fileslist[i]," \r")
# copy one file to a destination folder (full path composed with paste0())
file.copy(fileslist[i],paste0(destpath,unlist(strsplit(fileslist[i],"/"))[NoS+1]))
}

Resources