Archive files with certain extension - windows

So I need a Windows Script that I can tell it a directory to go through and it will parse all sub-directories and while in each subdir, will archive all files with a certain file extension and keep it in the same subdir, then move onto the next one.
What's the best way to go about this? Perl Automation Scripting, AutoIt?
Any sample code you guys can give me?

Perl is more powerful than batch scripts but since Perl is not included with windows it seems overkill for tasks such as this one. This should for example work:
FOR /R C:\hello\ %%G IN (*.txt) DO "c:\Program Files\7-Zip\7z.exe" a %%G.zip %%G && del %%G
Note that you cannot do this directly in the prompt, you must save it as a .bat file. It is of course also possible to allow the user to specify the paths and extensions with command line like this:
FOR /R %1 %%G IN (%2) DO "c:\Program Files\7-Zip\7z.exe" a %%G.zip %%G && del %%G
More information about FOR and other windows command line commands can be found here: http://ss64.com/nt/
This would then be run with:
test.bat C:\Hello\ *.txt
EDIT: This obviously requires you to have 7-Zip installed but it's pretty obvious where to change the code if you want to use some other zipper. Also keep in mind to always be Extremely careful when experimenting with scripts such as this. One small mistake could have it delete a lot of files, so you should always test it on a copy of the file system until you are absolutely sure it works.

FORFILES is included with Windows and may be more applicable than FOR to what you're trying to do:
FORFILES [/P pathname] [/M searchmask]
[/S]
[/C command] [/D [+ | -] {MM/dd/yyyy | dd}]
Description:
Selects a file (or set of files) and executes a
command on that file. This is helpful for batch jobs.
Parameter List:
/P pathname Indicates the path to start searching.
The default folder is the current working
directory (.).
/M searchmask Searches files according to a searchmask.
The default searchmask is '*' .
/S Instructs forfiles to recurse into
subdirectories. Like "DIR /S".
/C command Indicates the command to execute for each file.
Command strings should be wrapped in double
quotes.
The default command is "cmd /c echo #file".
The following variables can be used in the
command string:
#file - returns the name of the file.
#fname - returns the file name without
extension.
#ext - returns only the extension of the
file.
#path - returns the full path of the file.
#relpath - returns the relative path of the
file.
#isdir - returns "TRUE" if a file type is
a directory, and "FALSE" for files.
#fsize - returns the size of the file in
bytes.
#fdate - returns the last modified date of the
file.
#ftime - returns the last modified time of the
file.
To include special characters in the command
line, use the hexadecimal code for the character
in 0xHH format (ex. 0x09 for tab). Internal
CMD.exe commands should be preceded with
"cmd /c".
/D date Selects files with a last modified date greater
than or equal to (+), or less than or equal to
(-), the specified date using the
"MM/dd/yyyy" format; or selects files with a
last modified date greater than or equal to (+)
the current date plus "dd" days, or less than or
equal to (-) the current date minus "dd" days. A
valid "dd" number of days can be any number in
the range of 0 - 32768.
"+" is taken as default sign if not specified.

Below one way I would do it in AutoIt since you asked. Replace the MsgBox line with whatever code you need to do whatever it is your wanting to do. AutoIt is fun stuff!
#include <File.au3>
archiveDir(InputBox("Path","Enter your start path."))
Func archiveDir($rootDirectory)
$aFiles = _FileListToArray($rootDirectory)
For $i = 1 To UBound($aFiles) - 1
If StringInStr(FileGetAttrib($aFiles[$i]),"D") Then archiveDir($rootDirectory & $aFiles[$i] & "\")
MsgBox(0,"This would be your archive step!",'"Archiving" ' & $rootDirectory & $aFiles[$i])
Next
EndFunc

One solution could be:
my $dirCnt = 0;
traverse_directory('C:\Test');
sub traverse_directory{
my $directory = shift(#_);
$dirCnt++;
my $dirHandle = "DIR".$dirCnt;
opendir($dirHandle, $directory);
while (defined(my $file = readdir($dirHandle))){
next if $file =~ /^\.\.?$/; # skip . and .. ...
if (-d "$directory\\$file"){ traverse_directory("$directory\\$file"); }
if ($file =~ /\.txt/){ #find txt files, for example
print "$file\n"; #do something with the text file here
}
}
closedir($dirHandle);
}

Related

Run ffmpeg on all files of a folder [duplicate]

I need to convert some xls files into xlsx files. I can successfully convert one xls file into xlsx by running this command into cmd prompt (windows):
ssconvert inputFileName.xls outputFileName.xlsx
(ssconvert is a Gnumeric's command-line utility that can convert between different spreadsheet file formats)
I'd like to write a batch file that FOR EACH file in a specified directory runs the command I wrote above, using the current file name both for input and for output filename.
For example, if I have this set of files:
c:\directory\file1.xls
c:\directory\file2.xls
c:\directory\file3.xls
the output should be
c:\directory\file1.xlsx
c:\directory\file2.xlsx
c:\directory\file3.xlsx
so the batch pseudo code should be something like
directory = c:\directory\
for (fileName in directory)
ssconvert fileName.xls fileName.xlsx
Can anyone help me?
for /r %%v in (*.xls) do ssconvert "%%v" "%%vx"
a couple have people have asked me to explain this, so:
Part 1: for /r %%v in (*.xls)
This part returns an array of files in the current directory that have the xls extension. The %% may look a little curious. This is basically the special % character from command line as used in %PATH% or %TEMP%. To use it in a batch file we need to escape it like so: %%PATH%% or %%TEMP%%. In this case we are simply escaping the temporary variable v, which will hold our array of filenames.
We are using the /r switch to search for files recursively, so any matching files in child folders will also be located.
Part 2: do ssconvert "%%v" "%%vx"
This second part is what will get executed once per matching filename, so if the following files were present in the current folder:
c:\temp\mySheet.xls,
c:\temp\mySheet_yesterday.xls,
c:\temp\mySheet_20160902.xls
the following commands would be executed:
ssconvert "c:\temp\mySheet.xls" "c:\temp\mySheet.xlsx"
ssconvert "c:\temp\mySheet_yesterday.xls" "c:\temp\mySheet_yesterday.xlsx"
ssconvert "c:\temp\mySheet_20160902.xls" "c:\temp\mySheet_20160902.xlsx"
Actually this is pretty easy since Windows Vista. Microsoft added the command FORFILES
in your case
forfiles /p c:\directory /m *.xls /c "cmd /c ssconvert #file #fname.xlsx"
the only weird thing with this command is that forfiles automatically adds double quotes around #file and #fname. but it should work anyway
you can run something like this (paste the code bellow in a .bat, or if you want it to run interractively replace the %% by % :
for %%i in (c:\directory\*.xls) do ssconvert %%i %%i.xlsx
If you can run powershell it will be :
Get-ChildItem -Path c:\directory -filter *.xls | foreach {ssconvert $($_.FullName) $($_.baseName).xlsx }
I am doing similar thing to compile all the c files in a directory.
for iterating files in different directory try this.
set codedirectory=C:\Users\code
for /r %codedirectory% %%i in (*.c) do
( some GCC commands )

Find the number of rows in ~ 1000 CSV's using command

I'm running a process that produces n number of outputs at different timestamps for a given input CSV. The output files are in CSV form and labelled as such:
"Output" _ RouteName _ Direction _ YYMMDD _ HHMMSS
I have a macro that reports on missing data in the files, I just need a list of the number of rows in each CSV.
I have been doing this by using the command:
#Echo Off
:_Loop
If "%~1"=="" Pause&Goto EOF
Find /C /V "Wont#findthisin#anyfile" %1 >> LineCount.txt
Shift
Goto _Loop
The command is called counter.cmd and I just drag the output CSV's into it and it creates this output in a text file for each output:
---------- R:\10_TECHNICAL\10_TESTRUN\RUN\AM\ITN\A6_1N\OUTPUT_A6_1N_180313_070112.CSV: 5
The problem is that, I can only use this command to process a maximum of ~ 100 files, and I have ~ 1000 output files. When I try to make it do all 1000 files I get this error:
I have relatively basic windows command scripting skills and so don't know how to overcome this problem. Any help would be appreciated!
Before I get to the source of your problem, and the fix, I want to point out a couple things that could improve your current script.
1) Your FIND command can be simplified to find /n /v "" filePath - it seems nonsensical, but it works.
2) GOTO is relatively slow. You can get rid of the GOTO loop by using the FOR command to process all of the arguments. You can use %* to retrieve all of the arguments.
3) Every time you redirect the file must be opened and the file pointer positioned to the end of file. This takes time. It is much faster to redirect only once.
Incorporating all of the above, your script could be as simple as
#echo off
> LineCount.txt (for %%F in (%*) do find /n /v "" "%%F")
pause
When you drag files onto a batch script, it creates a single command line containing the path to each of the files. A Windows command line is limited to 8191 bytes long. So there is no way your strategy will work if you have ~1000 files.
I'm assuming all of your files are within a single folder, in which case you could change your script to process a single folder path instead of a list of file paths.
#echo off
>LineCount.txt (for %%F in ("%~1\*.csv") do find /n /v "" "%%F")
pause
If the files are spread across a few folders, then you can add an extra loop to iterate each of the folders
#echo off
>LineCount.txt ( for %%A in (%*) do for %%F in ("%%~A\*.csv") do find /n /v "" %%F")
pause
I have to assume the restriction is with your %1 variable and the maximum allowed command line length.
This can probably be easily remedied with a single command line
#Find /C /V "" R:\10_Technical\10_TestRun\Run\AM\ITN\A6_1N\*.csv > LineCount.txt
Edit
You can drag and drop the folder containing your csv files onto the batch file too.
If you want the outputfile in the same directory as the csv's then use:
#Find /C /V "" "%~1\*.csv" > "%~1\LineCount.txt"
Or in the same directory as the batch file:
#Find /C /V "" "%~1\*.csv" > "%~dp0LineCount.txt"
You could even have it output to the directory holding that folder:
#Find /C /V "" "%~1\*.csv" > "LineCount.txt"

Trouble with renaming folders and sub folders using Batch

So I'm trying to set up a template file structure for projects that can be modified in name to suit each project. I have created the example directory containing example folders i.e. "Template project" contains "template hardware" , "template software" etc. , and have a simple batch program that copies the "template project" folder and all contained subfolders, however I would like to change the word 'template' with what ever I choose to call the project. I was wondering if this is possible to do? Ideally I could just edit the batch file with the name of the project and then run it to copy the template and rename it.
Any help is greatly appreciated!
To start learning type help at the command prompt. Then anything on that list add /? for more help.
Set /p NewName=Enter project name
md "c:\somewhere\%newname%project\%newname% software
md "c:\somewhere\%newname%project\%newname% hardware
or use xcopy (and use/l to have it do a test without copying)
xcopy "c:\tempate" "d:\%newname%" /e /h /q /i /c
See set /?, md /?, and xcopy /?. Type just set to see a list of variables.
& seperates commands on a line.
&& executes this command only if previous command's errorlevel is 0.
|| (not used above) executes this command only if previous command's errorlevel is NOT 0
> output to a file
>> append output to a file
< input from a file
| output of one command into the input of another command
^ escapes any of the above, including itself, if needed to be passed to a program
" parameters with spaces must be enclosed in quotes
+ used with copy to concatinate files. E.G. copy file1+file2 newfile
, used with copy to indicate missing parameters. This updates the files modified date. E.G. copy /b file1,,
%variablename% a inbuilt or user set environmental variable
!variablename! a user set environmental variable expanded at execution time, turned with SelLocal EnableDelayedExpansion command
%<number> (%1) the nth command line parameter passed to a batch file. %0 is the batchfile's name.
%* (%*) the entire command line.
%<a letter> or %%<a letter> (%A or %%A) the variable in a for loop. Single % sign at command prompt and double % sign in a batch file.
\\ (\\servername\sharename\folder\file.ext) access files and folders via UNC naming.
: (win.ini:streamname) accesses an alternative steam. Also separates drive from rest of path.
. (win.ini) the LAST dot in a file path seperates the name from extension
. (dir .\*.txt) the current directory
.. (cd ..) the parent directory
\\?\ (\\?\c:\windows\win.ini) When a file path is prefixed with \\?\ filename checks are turned off.
< > : " / \ | Reserved characters. May not be used in filenames.
Reserved names. These refer to devices eg,
copy filename con
which copies a file to the console window.
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4,
COM5, COM6, COM7, COM8, COM9, LPT1, LPT2,
LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9
CONIN$, CONOUT$, CONERR$
Maximum path length 260 characters
Maximum path length (\\?\) 32,767 characters (approx - some rare characters use 2 characters of storage)
Maximum filename length 255 characters
Starting a Program
===============
See start /? and call /? for help on all three ways.
Specify a program name
--------------------------------
c:\windows\notepad.exe
In a batch file the batch will wait for the program to exit. When
typed the command prompt does not wait for graphical
programs to exit.
If the program is a batch file control is transferred and the rest of the calling batch file is not executed.
Use Start command
--------------------------
start "" c:\windows\notepad.exe
Start starts a program and does not wait. Console programs start in a new window. Using the /b switch forces console programs into the same window, which negates the main purpose of Start.
Start uses the Windows graphical shell - same as typing in WinKey + R (Run dialog). Try
start shell:cache
Use Call command
-------------------------
Call is used to start batch files and wait for them to exit and continue the current batch file.
.
--

Simple Batch Script for File Consolidation - Beginner Problems

I have identical files in four folders (named "1", "2", "3", "4") and would like to copy these files into a single folder, with the original folder name appended to the filename.
E.g. a file called "data.txt" in each folder should be copied to a new merged folder, with filenames such as "data 1.txt" "data 2.txt" etc.
Here is what I have so far, but I never formally learned batch scripting (and can't find any decent tutorials - recommendations please?) and can't seem to make it work. Hopefully this gives an idea of what I want to accomplish.
DIR="$( dirname "$0" )" && pwd )" // I don't understand this but was told it's
// necessary to set the working directory as
// the current folder? Is that correct?
md "consolidated files"
for %%i in ("1","2","3","4") do
copy *.txt '../consolidated files/"*"+%%i.txt'
Any tips for a beginner? Thanks!
#ECHO OFF
SETLOCAL
PUSHD "U:\sourcedir"
MD "consolidated files" 2>nul
for %%i in ("1","2","3","4") DO (
FOR /f "delims=" %%m IN ('dir /b /a-d ".\%%~i\*.txt"') DO (
copy ".\%%~i\%%m" ".\consolidated files\%%~nm %%~i%%~xm"
)
)
popd
GOTO :EOF
Your attempt to set dir appears to be a bash command - useful on *nix but no good on CMD.
Essentially, you can set the current directory using cd
cd "c:\your\desired directory"
Quirkishly, the quotes in that particular command are actually unnecessary (but do no harm, so I put them in.)
Another approach is
pushd "c:\your\desired directory"
rem commands following have current directory "c:\your\desired directory"
rem
popd
rem current directory reestored to value before the "pushd"
I've used the second approach in the above script to switch temporarily to my test directory U:\sourcedir
Note that cmd uses \ as a directory-separator and / as a switch-indicator.
The md command is as you had it. The directory is created relative to the current directory unless the path is specified (eg md "C:\somewhere new"). The2>nulsuppresses thedirectory already exists` message should the directory er, already exist.
in a for...do statement, either the target operation must be on the same line as the do or the do must be followed by Space( and then each statement until a matching ) is executed as a compound statement.
The for..%%i statement assigns the values "1".."4" (including the quotes) to %%i The quotes are actually not required in this case - they only need to be there if the required string includes a Space (or other separator.)
The next command is best understood from the middle. The dir command looks in ".\%%~i\" for files named *.txt. ~i means "remove quotes from %%i". The /b switch shows just filenames - no size, date or header/footer. The /a-d switch says 'no directories'.
This dir command is within single-quotes. FOR /f ...('single-quoted command')... processes the result of the command as if it was a file, line-by-line. The "delims=" suppresses the default tokenising of the strings found, so overall, the filenames found by the dir are assigned to %%m in their entirity.
The command then executed is the copy, copying from ".\%%~i\%%m" (ie. the current directory++the subdirectory(-quotes)++filename; all quoted in case of spaces) to ".\consolidated files\%%~nm %%~i%%~xm" (ie. the current directory+\consolidated files+the name part of the filename (%%~nm)+Space+the subdirectory(-quotes)+the extension part of the filename (%%~xm))
Note that + is a valid filename character (as is ') and that strings are built simply by being butted up one against the next.
Your original question stated that the source directoryname should be appended after a space, hence I've included the space.
Note that copy will report 1 file(s) copied after each copy. You can suppress this by adding >nul to the end of the copy statement.
For testing, I would change copy to echo copy which will show the command generated but not execute it. Unfortunately, if you have the >nul in place, the echo of the command will be suppressed...

Windows x64 & "parenthesis in path" batch file problem

Windows x64 versions contain folders named with parenthesis like "\Program Files (x86)" and this breaks a batch file I use. An example of a problem line:
for %%c in (%path%) do if exist "%%c\xyz.exe" set xyz=OK
i.e. when it reaches ")" in "(x86)" it puts out an error message and exits...
Any ideas on how to fix this?
This is a rather large batch file, and atm I don't have the time to rewrite it in a better language...
Many thanks :)
Doesn't directly answer your question, but if you are trying to do what I thinking you are trying (which is make sure a file exists in the path) you can use something like the following in a batch file.
#echo off
for %%i in (xyz.exe) do set xyz=%%~$PATH:i
if "%xyz%" == "" Goto NotFound
Echo "Found"
Goto TheEnd
:NotFound
Echo "Not found"
:TheEnd
Normally quoting should work, but in this case you want to iterate over all elements seperated by ;.
But you can replace the ; to a " " combination, so the brackets are quoted and you can iterate over the elements.
sample: path=C:\temp;C:\windows;C:\Program Files (x86)
The for-loop will search in
"C:\temp" "C:\windows" "C:\Program Files (x86)"
As code it looks like
setlocal EnableDelayedExpansion
set "searchPath=!path:;=" "!"
for %%c in ("!searchPath!") do (
if exist "%%~c\xyz.exe" set xyz=OK
)
You can use the short names of the folder for this purpose. This is how you do it.
Open command promt in Windows.
Go to C drive (or the drive in which you have the Program Folder)
Type the following and
c:\> dir /x <Hit Enter>
This will return the short forms of all folders.
You will notice now that "\Program Files (x86)" will be represented as "PROGRA~2" (or an equivalent short name).
This is what I use to prevent any errors while creating Batch scripts.
For more options see here.
http://www.computerhope.com/dirhlp.htm
Exlpanation for "dir /x"
"This displays the short names generated for non-8dot3 file names. The format is that of /N with the short name inserted before the long name. If no short name is present, blanks are displayed in its place."

Resources