Checking the integrity of zip archives recursively how can i rename bad files in a folder by appending a string after the file extension via a batch file under Windows?
I tried this script and it gives me no errors but doesn't rename bad files either.
FOR /R \backup %%A IN (*.zip) DO (
7z t "%%A" | FIND "Everything is Ok" || ((REN "%%A" "%%A.bad") & (ECHO.%%A BAD >> error.log))
)
I have experience in PHP scripting and understand this code block in general (the meaning of the pipe and the logical OR operator). However, i have absolutely no experience in Batch-scripting and adopted the script from this source. From what i understand the check receives either an "OK" or adds an entry to the log file and renames the file. The log entry is added, however the renaming is not applied. I don't understand why. Can you tell me what is going wrong and how it would have to look to work as intended?
You can use this batch code for your task.
#echo off
rem Test all ZIP files recursive from directory backup in root of
rem current drive and append .bad to those ZIP files not validate.
rem The names of those files are additionally written into an
rem error.log text file in current working directory.
for /R "\backup" %%A in (*.zip) do (
7z.exe t "%%A">nul
if errorlevel 1 (
ren "%%A" "%%~nxA.bad"
echo %%A BAD>>error.log
)
)
In help of 7-zip there is a page about Exit Codes. As it can be read on this help page any value greater 0 means something was wrong.
Therefore if errorlevel 1 can be used to check if the test on the ZIP file was positive (exit code is 0) or failed (value is greater or equal 1).
Look on help output in a command prompt window after entering if /? or help if for details about errorlevel. if errorlevel 1 means: if exit code of previous command was greater or equal 1 then ...
Further command ren requires just new file name without path as second parameter as otherwise it does not rename the file specified with or without path as first parameter. This is the reason why %%~nxA must be used as second parameter for command ren to reference just name and extension of the file to rename. Help of command for output after entering for /? or help for contains a list of those modifier letters for a file name.
Related
I was trying to move my files(books) based on it's author name.
For example:
[author] Title 1.pdf
[author2] Title A.pdf
I've found a batch script for this
#echo off
for %%i in (*) do (
if not "%%~ni" == "organize" (
md "%%~ni" && move "%%~i" "%%~ni"
)
)
It works but it made each folder for each files, what I want to do is create folder by author names and move it there.
Note: All author name have "[]" in it's file name but the folder created only has author name without "[]".
Please help, I have 4000+ files I need to sort.
The following script uses a for /F loop to split the file names which are gathered by the dir command:
#echo off
for /F "tokens=1* delims=[] eol=]" %%I in ('dir /B /A:-D-H-S "[*]*.pdf"') do (
ECHO md "%%I" 2> nul
ECHO move "[%%I]%%J" "%%I\"
)
The 2> nul portion suppresses error messages in case the directory to create already exists.
After having tested for the correct output, remove the upper-case ECHO commands from the md and move command lines. To avoid multiple 1 file(s) moved. messages, append SPACE + > nul to the move command line.
The trailing \ at the destination of the move command is intended to force it to point to a directory. Imagine the destination directory could not be created for some reason (for example, lack of access privileges), the destination without the \ is interpreted as a new file name in the working directory, leading to unintentional renaming; with the \ the move command expects an existing directory, and if not found an error arises.
Besides the fact that your code did not attempt to split the file names as needed, there is one additional problem: the && operator lets the following command execute only in case of success of the former one; so when md failed, move does not run. For example, you have got two files with the same author, so when iterating the second one, the destination directory already exists since it has been created in the previous iteration, so md fails and the respective file is not moved. Therefore you should have used the unconditional & operator.
Ok, i've been working on a batch file for some time now, and im just stuck on the last bit.
What im trying to accomplish is to loop through a directory, create a variable which stores the filename of each file in the directory without the extension. Then for each file in the first loop, loop through a different directory and try to find any filename in the second loop that has the same name as stored in the variable, and then just output some simple text.
So for instance lets say in the first directory there is a filename called imafile-yehyeh.png, the variable will save imafile-yehyeh, then it will loop through all the files in the second directory, and output a message for each filename that has that pattern in it, so if a file in the second directory is called imafile-yehyeh_01.mp4 or imafile-yehyeh-newtitle.jpg, they would match the pattern and a message would output.
My script is looping and i am able to echo out all the variables, the files exist as i have created them exactly as shown above, but its not echoing out the filename is set for deletion line.
Any help would be greatly appreciated. my code is as follows;
#echo off
set "parent_folder=C:\Users\Testing\script"
set "dupe_folder=DUPEFOLDER"
set "kill_folder=1 SCANNED\thumb"
setlocal enableDelayedExpansion
for %%X in ("%parent_folder%\%dupe_folder%\*") do (
set dupe_pattern=%%~nX
for %%F in ("%parent_folder%\%kill_folder%\*") do (
echo %%~nF | FIND "%dupe_pattern%" 1>NUL && (
echo %%~F is set for deletion.
)
)
)
endlocal
Thanks to #Squashman the answer was to remove the set dupe_pattern.... line
and then change the FIND command to the following;
FIND "%%~nX"
Apart from needlessly setting a variable, as already pointed out, you are also making the script inefficient. For every file in the dupe_folder you are Echoing every file name in the kill_folder and piping that into a Find command looking for matches.
Here's a simpler way of doing it, (it matches file names which begin with the same string followed by a dot, as opposed to any file name containing the string anywhere).
#Echo Off
Set "parent_folder=C:\Users\Testing\script"
Set "dupe_folder=DUPEFOLDER"
Set "kill_folder=1 SCANNED\thumb"
CD /D "%parent_folder%" 2>Nul || Exit /B
For %%A In ("%kill_folder%\*") Do If Exist "%dupe_folder%\%%~nA.*" (
Echo %%A is set for deletion.)
I have a landing directory where we receive 10-15 files everyday. I then run a batch script to create a list with file names that have newly landed and then informatica reads the list of file names to process the new source files.
The problem here is, if a file is edited on same day after informatica loads the file. My batch script does not identify the updated file because the file has same date and name.
Is there a way to compare files based on timestamp and generate a file list? Any help will be greatly appreciated. Thanks!
The current batch script code:
rem this batch script is used to list all the files hosted newly to a xyz landing directory
set LandingDir=\\path\to\landing\directory\*.csv
set DateFile=%sys_var%\script\DateFile.txt
set LastRunDateFile=%sys_var%\scripts\LastRunDateFile.txt
set Temp_File_List=%sys_var%\scripts\Temp_File_List.txt
set File_List=%sys_var%\SrcFiles\File_List.txt
set /P _PreviousDate=<%DateFile%
type %DateFile% > %LastRunDateFile%
xcopy "%LandingDir%" /l /s /d:%_PreviousDate% .>%Temp_File_List%
type %Temp_File_List% | findstr /v File(s)>%File_List%
echo %date:~4,2%-%date:~7,2%-%date:~10,4% >%DateFile%
On Windows there is the archive attribute always set on a file automatically if a file is modified in any way.
Using the archive file attribute makes the task much easier than storing last modification files times of all files processed and comparing last modification file times on next run.
All needed to be done is removing archive attribute on file being already processed, i.e. added to the file list.
Example:
#echo off
setlocal
set "FilePattern=*.csv"
set "sys_var=C:\Temp\Test"
set "File_List=%sys_var%\SrcFiles\File_List.txt"
set "LandingDir=\\server\share\path\to\landing\directory"
if exist "%File_List%" del "%File_List%"
for /F "delims=" %%I in ('dir "%LandingDir%\%FilePattern%" /AA-D /B 2^>nul') do (
echo %LandingDir%\%%I>>"%File_List%"
%SystemRoot%\System32\attrib.exe -a "%LandingDir%\%%I"
)
if not exist "%File_List%" echo No new file!
endlocal
The command DIR returns because of /AA-D just files (not directories) with archive attribute set in bare format because of /B.
So output by DIR and processed by FOR are just the names of the files with archive attribute set without path and always without surrounding double quotes even if the file name contains a space or another special character.
The file names would be returned by DIR with full path on using additionally DIR option /S for listing recursively all files in specified directory and in all subdirectories matching the file pattern (and having archive attribute set).
Each file name is written into the file list file and then the archive attribute is removed from the file to ignore this file automatically on next run of the batch file except the archive attribute is set again because the file was modified in the meantime.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
attrib /?
del /?
dir /?
echo /?
endlocal /?
for /?
set /?
setlocal /?
See also the Microsoft article Using command redirection operators for an explanation of >> and 2>nul with escaping > with ^ to be interpreted on execution of DIR instead of FOR.
I have written the following .bat file, and it runs perfectly on my Windows 2000 machine, but will not run on my Windows 7 or Windows XP machines. Basically it just loops through the current directory and runs a checksum program which returns the checksum. The output of the program is saved to a text file and then formatted to remove the checksum of the output file.
#Echo Off
for /r %%f in (*.txt) do crc32sum.exe %%f >> all_checksums.txt
ren all_checksums.txt old.txt
findstr /v /e /c:"all_checksums.txt" old.txt > all_checksums.txt
del old.txt
When I run this file on my Win2k PC with a bunch of text files and the crc32sum.exe in a folder, it outputs the file. On other machines it outputs a blank file. I turned Echo on and kept only the for loop line and found that the output from executing the crc32sum.exe is nothing. If you manually run the crc32sum.exe file it outputs the checksum no problem.
Any ideas as to how to fix this?
EDIT: Here is a link to the software: http://www.di-mgt.com.au/src/digsum-1.0.1.zip
EDIT2: New development, it seems that the file works if the path of the folder has no spaces in it i.e. C:\temp or C:\inetpub\ftproot or C:\users\admin\Desktop\temp. Does anyone know how I can make this work with paths that have spaces? %%~f doesnt work it says unexpected.
Try this modified batch code which worked on Windows XP SP3 x86:
#echo off
goto CheckOutput
rem Command DEL does not terminate with an exit code greater 0
rem if the deletion of a file failed. Therefore the output to
rem stderr must be evaluated to find out if deletion was
rem successful or (for a single file) the file existence is
rem checked once again. For details read on Stack Overflow
rem the answer http://stackoverflow.com/a/33403497/3074564
rem The deletion of the file was successful if file created
rem from output message has size 0 and therefore the temp
rem file can be deleted and calculation of the CRC32 sums
rem can be started.
:DeleteOutput
del /F "all_checksums.txt" >nul 2>"%TEMP%\DelErrorMessage.tmp"
for %%E in ("%TEMP%\DelErrorMessage.tmp") do set "FileSize=%%~zE"
if "%FileSize%" == "0" (
set "FileSize="
del "%TEMP%\DelErrorMessage.tmp"
goto CalcCRC32
)
set "FileSize="
echo %~nx0: Failed to delete file %CD%\all_checksums.txt
echo.
type "%TEMP%\DelErrorMessage.tmp"
del "%TEMP%\DelErrorMessage.tmp"
echo.
echo Is this file opened in an application?
echo.
set "Retry=N"
set /P "Retry=Retry (N/Y)? "
if /I "%Retry%" == "Y" (
set "Retry="
cls
goto CheckOutput
)
set "Retry="
goto :EOF
:CheckOutput
if exist "all_checksums.txt" goto DeleteOutput
:CalcCRC32
for /R %%F in (*.txt) do (
if /I not "%%F" == "%CD%\all_checksums.txt" (
crc32sum.exe "%%F" >>"all_checksums.txt"
)
)
The output file in current directory is deleted if already existing from a previous run. Extra code is added to verify if deletion was successful and informing the user about a failed deletion with giving the user the possibility to retry after closing the file in an application if that is the reason why deletion failed.
The FOR command searches because of option /R recursive in current directory and all its subdirectories for files with extension txt. The name of each found file with full path always without double quotes is hold in loop variable F for any text file found in current directory or any subdirectory.
The CRC32 sum is calculated by 32-bit console application crc32sum in current directory for all text files found with the exception of the output file all_checksums.txt in current directory. The output of this small application is redirected into file all_checksums.txt with appending the single output line to this file.
It is necessary to enclose the file name with path in double quotes because even with no *.txt file containing a space character or one of the special characters &()[]{}^=;!'+,`~ in its name, the path of the file could contain a space or one of those characters.
For the files
C:\Temp\test 1.txt
C:\Temp\test 2.txt
C:\Temp\test_3.txt
C:\Temp\TEST\123-9.txt
C:\Temp\TEST\abc.txt
C:\Temp\TEST\hello.txt
C:\Temp\TEST\hellon.txt
C:\Temp\Test x\test4.txt
C:\Temp\Test x\test5.txt
the file C:\Temp\all_checksums.txt contains after batch execution:
f44271ac *test 1.txt
624cbdf9 *test 2.txt
7ce469eb *test_3.txt
cbf43926 *123-9.txt
352441c2 *abc.txt
0d4a1185 *hello.txt
38e6c41a *hellon.txt
1b4289fa *test4.txt
f44271ac *test5.txt
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
cls /?
del /?
echo /?
for /?
goto /?
if /?
rem /?
set /?
type /?
One of the help pages output on running for /? informs about %~I, %~fI, %~dI, %~pI, %~nI, %~xI, %~sI, %~aI, %~tI, %~zI.
Using in a batch file f (in lower case) as loop variable and referencing it with %%~f is a syntax error as command processor expects next the loop variable. %%~ff would be right, but could be different to %%~fI (name of a file/folder with full path and extension without quotes) in comparison to %%~I (string without surrounding quotes).
It is not advisable to use (those) small letters as loop variable. It is better to use upper case letters or character # as loop variable. The loop variable and also those modifiers are case sensitive while nearly everything else in a batch file is case insensitive.
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...