How do I create a batch file that will copy files from a camera to a directory that is prompted from the command line?
example folder structure: {shared drive start folder} <year> <month> <(prompt user for name)> [delete pictures after copied]
I am looking to get this to work to copy pictures from various cameras to one shared folder and have it all sorted by year then month and finally by the user prompted name. I know very little command line commands, all the switches and %'s.. i get lost pretty quickly.
Windows 7 computers and most likely SD cards in readers because most of the cameras don't show up with drive letters (this is part of my problem)
The code:
Show errors:
ECHO ON
type of file:
SET type=jpg
to set where the files are going:
NET USE M:\public\am_class\
to get user input i would use "SET /P" so i would do:
SET /P SDdrive=Enter Sd Card drive letter:
Get month and year(and day in case its needed later) to create initial folders:
FOR /F "TOKENS=1* DELIMS= "%%A IN ('DATE/T') DO SET CDATE=%%B
FOR /F "TOKENS=1,2 eol=/ DELIMS= "%%A IN ('DATE/T') DO SET mm=%%B
FOR /F "TOKENS=1,2 DELIMS=/ eol=/ "%%A IN ('echo %CDATE%') DO SET dd=%%B
FOR /F "TOKENS=2,3 DELIMS=/ "%%A IN ('echo %CDATE%') DO SET yyyy=%%B
SET date=%mm%%dd%%yyyy%
change dir to the correct location... this im not sure about but the "NET USE" gives me a direction to look in (figured out and placed correct code):
cd\
cd /DM:\public\am_class\"
make new folders in above main folder
mkdir "%yyyy%"
cd "%yyyy%"
mkdir "%mm%"
cd "%mm%"
!!next question is this correct to get it to create a folder from the user prompted info? (This is corrected and correct)
SET /P foldername=Please enter assignment number and press enter:
mkdir "%foldername%"
cd "%foldername%"
Go to SDdrive:
%SDdrive%
Find the Path of the files:
FOR /F "TOKENS=2 DELIMS\" %%A IN ('dir /b /s *.%type%') DO SET p1= %%A
Change folder and copy to "foldername" folder
CD"%p1%"
COPY *.* %foldername%
Delete the SDcard pics after complete:
Set /P delete=Delete SD card pictures (y/n)?
IF /I "%delete%"=="y" GOTO delY
IF /I "%delete%"=="y" GOTO delN
:delY
%SDdrive%
del /q *.*
explorer.exe \\landis.xxx\public\am_class\%foldername%\
:delN
explorer.exe \\landis.xxx\public\am_class\%foldername%\
Pause for testing only (will be removed in final version):
Pause
I hope that helps some.
Use the net use command to map the windows share to a drive like X:\ and then use
xcopy with some appropriate arguments to copy the files.
Like I said in my comment, your question is very broad with a lot of things to consider. I wrote a batch-file that I have used for years on many versions of Windows to download my pictures from SD cards. It does a good job, but it does not take into account that two different SD cards may have the same picture names on them -- even though they are different pictures. It simply skips pictures that have already been downloaded with the same filename in the destination folder.
I'm not going to write your code for you, nor do I have the time right now to help you navigate your way through learning the batch-file language, but I can at least post the two batch files that I use so that you can see some of the techniques that I used to accomplish what you're trying to do.
I created a shortcut in the SendTo folder that points to the DownloadPictures.bat so that when I insert an SD card into the card reader, I can send the images folder on the SD card to the shortcut and it downloads all of the pictures, separating them into folders based on the year/month/day they were taken. Then it opens each distinct destination folder using explorer.exe. The CMD window does not show anything during the download (i.e., nothing is echoed to the window), however, the title shows the overall progress and current image filesize (e.g., "1/300 7341254 bytes").
In order to grep the year, month and day from the file dates, I use another batch-file I wrote called SubStr.bat that lets me get a substring of the output of any DOS command and assign it to a variable. You must use Delayed Command Line Expansion for everything to work.
Please remember that this is not meant to be a solution for your question, but is simply an example that shows how to do some of what you are asking -- so that you can use it as a reference as you work on your own solution.
DownloadPictures.bat
#echo off
setlocal ENABLEDELAYEDEXPANSION
cd /d c:\
title Counting the files to download...
set _total=0
for /f "delims=" %%i in ('dir %1 /a-d /b /s') do set /a _total+=1
set _cnt=0
for /f "delims=" %%i in ('dir %1 /a-d /b /s') do (
set /a _cnt+=1
if /I "%%~xi" neq ".ctg" (
title !_cnt!/%_total%: %%i - %%~zi bytes
call substr "echo %%~ti" _date 0 n n "" sub 0 10
call substr "set _date" _year 0 n n "" end 4
call substr "set _date" _month 0 n n "" sub 6 2
call substr "set _date" _day 0 n n "" sub 9 2
set _dir=Q:\Photographs\Downloads\!_year!.!_month!.!_day!
md !_dir! > nul 2>&1
if not defined _old_dir set _old_dir=!_dir!
if "!_dir!" neq "!_old_dir!" (explorer !_dir!&set _old_dir=!_dir!)
if not exist !_dir!\%%~nxi copy %%i !_dir! > nul 2>&1
)
)
explorer !_dir!
echo All the pictures in directory %1 have been downloaded.
endlocal
SubStr.bat
#echo off
if "%7"=="" goto Help
:ExtractString
:: Remove the first and last " and convert all "" to ".
set __command_=%1
set __command_=%__command_:""="%
set __command_=%__command_:~0,-1%
set __command_=%__command_:~1%
:: Execute the command and direct the output to a unique file.
%__command_% > %TEMP%\_záfileáz_
:: Extract the specified line from the output file. (Note: You can't use 'skip'
:: with a value of '0'.) I used '«' as the delimiter because it is a character
:: that I will never encounter and this will ensure that I get the whole line
:: returned from the 'for' statement.
if "%3"=="0" (
for /f "delims=«" %%i in (%TEMP%\_záfileáz_) do if not defined _závaráz_ (set _závaráz_=%%i)
) else (
for /f "skip=%3 delims=«" %%i in (%TEMP%\_záfileáz_) do if not defined _závaráz_ (set _závaráz_=%%i)
)
if /i "%7"=="all" goto Finish
if /i "%7"=="sub" set _závaráz_=!_závaráz_:~%8,%9!
if /i "%7"=="end" set _závaráz_=!_závaráz_:~-%8!
:Finish
:: Kill spaces, quotes.
if /i "%4"=="y" set _závaráz_=%_závaráz_: =%
if /i "%5"=="y" set _závaráz_=%_závaráz_:"=%
:: Remove unwanted characters (pad the front with an unlikely string so that the
:: FOR statement will never complain because of an empty set). The %%~i notation
:: strips quotes out of the string and spaces are delimiters. This is why they
:: each (spaces and quotes) have their own parameters above...
set __remove_=%6
set __remove_=ßa¯¦¯aß %__remove_:~1%
set __remove_=%__remove_:~0,-1%
set __remove_=%__remove_:""="%
for %%i in (%__remove_%) do set _závaráz_=!_závaráz_:%%~i=!
:: Set the output variable.
set %2=!_závaráz_!
:Cleanup
set _závaráz_=
del %TEMP%\_záfileáz_
set __command_=
set __remove_=
goto TheEnd
:Help
echo.
echo SubStr
echo ================================================================================
echo.
echo Syntax:
echo.
echo SubStr ["command"] [output variable] [Lines to Skip] [Remove Spaces]
echo [Remove Quotes] [Remove Other] [action [var1] [var2]]
echo.
echo Parameters:
echo.
echo Command - The command that creates the output characters. If the
echo command includes calling another batch file, issue the
echo command by using the 'call' function
echo (e.g., "call another.bat"). When your command is passed,
echo it must be enclosed in quotes. If part of the command needs
echo to also have quotes (i.e., for long filenames), the strings
echo within the command that need to be quoted need to be double
echo quoted (e.g., "dir ""c:\win 2000\notepad.exe"" /x"). When
echo the command is executed, the initial and final quotes will
echo be stripped off and all sets of double quotes ("") will be
echo replaced with single quotes (").
echo.
echo Output Variable - The name of the variable to use (set var=copied text).
echo.
echo Lines to Skip - The number of lines before the line from which you want to
echo copy text.
echo.
echo Remove Spaces - Removes spaces out of the copied text.
echo.
echo Remove Quotes - Removes quotes from the copied text.
echo.
echo Remove Other - A string of strings that should be removed from the copied
echo text. The set of strings or characters must be enclosed in
echo a single set of double quotes. At times, some characters
echo may not be elimated (e.g., a comma) unless it too is
echo enclosed in quotes. To do this, the quotes must be doubled.
echo For example: "a b c d "","" e f h"
echo.
echo Action - Action to perform:
echo All - Copies entire string.
echo Sub - Extracts part of the string where var1 is the
echo starting position and var2 is the number of
echo characters to copy. var1 is zero based. A negative
echo value for var2 omits the specified number of
echo characters from the end of the string.
echo End - Only extracts the specified number of characters
echo from the end of the string (specified by var1).
echo.
echo Example:
echo.
echo SubStr "dir c:\windows\system32\notepad.exe /-c" _filesize 5 y n "" sub 20 18
echo.
echo This command assigns the size of notepad.exe to the variable _filesize.
echo Try running it and then type 'set _' at the command prompt.
echo.
echo Notes:
echo.
echo Make sure delayed command line expansion is enabled in the calling batch file
echo via the "setlocal ENABLEDELAYEDEXPANSION" command, or enable it globally by
echo editing the registry as follows (and then reopen your CMD windows):
echo.
echo Location: HKEY_CURRENT_USER\Software\Microsoft\Command Processor
echo Item: DelayedExpansion
echo Type: dword
echo Value: 1
echo.
echo ================================================================================
echo.
:TheEnd
Thank you James L and User.
James:
Post 1: I though about asking some one to do it for me but then I would never learn anything from it. ignoring your telling me to the the towel in i got a working program.
Post 2: Very very useful post. Not only did it have code (i got to work no problem) you gave a description of how you used it. the first code is going to take me a while to decode what is what and how you did it. The second code it VERY HELPFUL, its well documented and i understand more of whats going on it it.
User:
This ended up being what i used to get my program to work. I had to keep it simple :)
Thank you both for your help with this posted problem.
James: thank you very much for all the code and useful information that your second post was teeming with.
This is the final working code for copying pictures from an SD card to a specific user named folder sorted by year then month then project name. This is set for the SD Drive to be drive letter "F:" you can change it to what you need or delete "#SET cameradrive=F:" and remove the "REM" from the line above and it will prompt the user for the drive letter. It takes the user input and makes it all capitals to make a cleaner looking folder. One thing to note: this doesn't work if the folder name has a space in it. I have to figure out how to fix that (ill be posting a question on it here). It then opens the folder in explorer so you can verify that everything went OK. After you have checked then you can delete the files on the SD card by pressing "y" and hitting enter. If you don't want to delete them then press "n" and hit enter. This copies EVERY PICTURE on the SD card in the nested folder so if you have multiple photos you want to go different places this wont work for you. also if your pictures aren't jpg then just change the "SET type=" to what ever your file type is. I placed a program called "USB Ejector" into the root of the SD card so that when the batch file is completed it automatically safely removes the card from windows.
# echo on
# SET type=jpg
# SET userfolder=C:
#cd /dy:\landis\public\am_class
#REM SET /P cameradrive=Enter Camera Drive Letter (ie D:) and hit Enter:
#SET cameradrive=F:
set /p foldername=Type Folder name and hit Enter:
#REM This makes everything uppercase.
# SETLOCAL ENABLEDELAYEDEXPANSION
# SET _SAMPLE="%foldername%"
# CALL :UCase _SAMPLE _RESULTS
# ECHO.%_RESULTS%
# CALL :LCase _SAMPLE _RESULTS
# ECHO.%_RESULTS%
# ENDLOCAL
# GOTO:EOF
# :LCase
# :UCase
# :: Converts to upper/lower case variable contents
# :: Syntax: CALL :UCase _VAR1 _VAR2
# :: Syntax: CALL :LCase _VAR1 _VAR2
# :: _VAR1 = Variable NAME whose VALUE is to be converted to upper/lower case
# :: _VAR2 = NAME of variable to hold the converted value
# :: Note: Use variable NAMES in the CALL, not values (pass "by reference")
# SET _UCase=A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
# SET _LCase=a b c d e f g h i j k l m n o p q r s t u v w x y z
# SET _Lib_UCase_Tmp=!%1!
# IF /I "%0"==":UCase" SET _Abet=%_UCase%
# IF /I "%0"==":LCase" SET _Abet=%_LCase%
# FOR %%Z IN (%_Abet%) DO SET _Lib_UCase_Tmp=!_Lib_UCase_Tmp:%%Z=%%Z!
# SET %2=%_Lib_UCase_Tmp%
#REM GOTO:EOF
#REM
# SET foldername=%_RESULTS%
#REM SETTING THE YEAR AND MONTH VARIABLES
# SET yyyy=%date:~10,4%
# SET mm=%date:~4,2%
#REM CREATING THE FOLDERS WITH THE NAMES AND NESTING THEM CORRECTLY
# mkdir %yyyy%
# cd %yyyy%
# mkdir "MSU Orders"
# cd "MSU Orders"
# mkdir %mm%
# cd %mm%
# mkdir "%foldername%"
# cd "%foldername%"
#REM COPY THE CONTENTS OF THE CAMREA PIC FOLDER TO THE NEW FOLDER
# xcopy /e /v %cameradrive%\DCIM\100NIKON "\\landis\public\am_class\%yyyy%\%mm%\%foldername%\"
# explorer.exe \\landis\public\am_class\%yyyy%\%mm%\%foldername%\
#REM Delete the originals prompt and then actions
# SET /P delete=Delete Original Photos from Camera (y/n)?
# IF /I %delete%==y GOTO :dely
# IF /I %delete%==n GOTO :deln
# GOTO :deln
# :dely
# cd /d%cameradrive%\DCIM\100NIKON
# del /q *.*
# GOTO :done
# :deln
# GOTO :done
# :done
# cd /dc:\
# F:\USB_Disk_Eject.exe /removethis
# pause
Related
Okay here is what I got so far.
This is meant to add websites to block in the hosts file, as well as allow the user to delete the entries when they want to. When trying to add a website to block sometimes it creates a new line then puts the entry on the line before it. This is not what I want. I want it to create a new line then add the entry on that line. For some reason it works sometimes and other times it don't work at all. I get an error message that says Find parameter is incorrect. I am using the Find command to see if the entries is already in the hosts file. If it is I want it to avoid adding it. If it is not then I want to add it. When I try to delete a entry the batch just crashes, so I am not really sure what I am doing wrong here. I am trying to find the entry and replace it with nothing. What I really want to do is delete the entire line so that I don't end up with a lot of blank lines.
Any help is greatly appreciated. Thanks!
#echo off
TITLE Modifying your HOSTS file
COLOR F0
:LOOP
cls
SET "CHOICE="
ECHO Choose 1 to block a website
ECHO Choose 2 remove a blocked website
ECHO Choose 3 to exit
SET /P CHOICE= selection %CHOICE%
GOTO %CHOICE%
:1
cls
SET /P WEBSITE=Enter the name of the website to add:
SET HOME= 127.0.0.1
SET NEWLINE=^& echo.
SET BLOCKEDSITE=%HOME% %WEBSITE%
FIND /C /I %BLOCKEDSITE% %WINDIR%\system32\drivers\etc\hosts
IF %ERRORLEVEL% NEQ 0 ECHO %NEWLINE%^%BLOCKEDSITE%>>%WINDIR%\System32\drivers\etc\hosts
ECHO Website blocked
ping 127.0.0.1 -n 5 > nul
GOTO LOOP
:2
cls
SET /P WEBSITE=Enter the name of the website to remove:
SETLOCAL ENABLEEXTENTIONS DISABLEDELAYEDEXPANSION
SET "HOME= 127.0.0.1 "
SET "BLOCKEDSITE=%HOME% %WEBSITE%"
SET "REPLACE="
SET "HOSTSFILE=%WINDIR%\system32\drivers\etc\hosts"
FOR /F "DELIMS=" %%i IN ('TYPE "%HOSTSFILE%" ^& BREAK ^> "%HOSTSFILE%" ')
DO
(
SET "LINE=%%i"
SETLOCAL ENABLEDELAYEDEXPANSION
>>"%HOSTSFILE%" echo(!LINE:%BLOCKEDSITE%=%REPLACE%!
ENDLOCAL
)
ECHO Website unblocked
GOTO LOOP
:3
EXIT
Please note that the term website is misleading when referring to the entries of the hosts file. The entries of hosts file are used for custom mappings of DNS host names to IP addresses, and any host name that is present in the file does not necessarily hosts a website. Using the term website may lead to the false impression that something like http://www.example.com can be added to hosts file which is not true.
Skipping a host if it is already present in the hosts file:
The problem with your usage of find is that %BLOCKEDSITE% has embedded spaces so you should enclose it quotes and use:
FIND /C /I "%BLOCKEDSITE%" %WINDIR%\system32\drivers\etc\hosts
But it has another problem: Because of its dependency on the exact spacing between the IP address and host name which is mandated by %BLOCKEDSITE% It only works for the entries that are added by your batch file. Additionally the user may have commented out (disabled) an entry by placing # in the begging of the line that contains the entry, and your batch code will skip adding the host even if the entry is disabled.
This can be resolved by using findstr with its regex syntax. for example:
findstr /IRC:"^ *127\.0\.0\.1 *example\.com *$" "%WINDIR%\system32\drivers\etc\hosts"
Removing an entry from the hosts file:
In the FOR loop you just have to skip writing the lines that contains the specified entry:
if "!Line!"=="!LINE:%BLOCKEDSITE%=!" echo(!Line!>>"%HOSTSFILE%"
But again it is not accurate and is suffering from the same problems that are mentioned earlier for skipping adding the entry. Again By using findstr you can easily remove the lines that contain the unwanted entry:
findstr /VIRC:"^ *127\.0\.0\.1 *example\.com *$" "%HOSTSFILE%" > "%HOSTSFILE%.tmp"
del "%HOSTSFILE%"
ren "%HOSTSFILE%.tmp" "hosts"
With above mentioned points the script can be rewritten like this:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
title Modifying your HOSTS file
color F0
set "HOSTSFILE=%WINDIR%\system32\drivers\etc\hosts"
set "HOME=127.0.0.1"
set "PROMPT_TEXT=Enter the host name to"
set "ACTION_TEXT[1]=add"
set "ACTION_TEXT[2]=remove"
set "FindEmptyLine=^ *$"
set "NewLineAppended="
cls
setlocal EnableDelayedExpansion
:LOOP
echo,
echo 1. Block a host
echo 2. Remove a blocked host
echo 3. Exit
choice /C "123" /N /M "Choose an item [1, 2, 3]: "
set "Item=%errorlevel%"
goto choice%Item%
:choice0 // User Pressed CTRL-C
:choice3
exit /b
:choice1
call :Common
set "HostEntry=!HOME! !HOST!"
findstr /IRC:"!FindEntry!" "!HOSTSFILE!"> nul && (
echo The host !HOST! is already blocked, No action taken.
) || (
if not defined NewLineAppended (
REM This will append a new line ONLY if the file does not end by LF character
type "!HOSTSFILE!" | findstr $ > "!HOSTSFILE!.tmp" && (
del "!HOSTSFILE!"
ren "!HOSTSFILE!.tmp" "hosts"
set "NewLineAppended=1"
)
)
echo !HostEntry!>>"!HOSTSFILE!"
echo The host !HOST! blocked
)
goto LOOP
:choice2
call :Common
findstr /VIR /C:"!FindEntry!" /C:"!FindEmptyLine!" "!HOSTSFILE!">"!HOSTSFILE!.tmp" && (
del "!HOSTSFILE!"
ren "!HOSTSFILE!.tmp" "hosts"
echo The host !HOST! unblocked
)
goto LOOP
:Common
set "HOST="
set /P "HOST=!PROMPT_TEXT! !ACTION_TEXT[%Item%]! (e.g. example.com): "
if not defined HOST (
(goto)2>nul
goto LOOP
)
set "FindEntry=^^ *!HOME! *!HOST! *$"
set "FindEntry=!FindEntry:.=\.!"
exit /b
I am a serious newbie at creating batch files and am hoping someone can help me. One of our staff receives zipped pdf docs by email, which she copies to a folder on her desktop. Within that folder, I would like for her to run a batch script that will
A. Unzip the zipped contents into a network directory, i.e. \server\contracts
Under this directory, the process will create folders for each group of contracts, i.e. \server\contracts\Masterson (The name of this will be same as zipped file name).
B. Then the batch process should copy a select few of the pdf documents into a network directory based on the filename. Each file contains a number, which will go in the following manner: Masterson + 1.pdf >> \server\contracts\Item1 and \server\contracts\Item2, etc. Masterson + 1.pdf will go into \server\contracts\Item1 without a folder name, as will Paisley + 1 certificate.pdf and Johnsonville + 1 document.pdf.
The problem is that the companies do not follow instructions and the number can be at the beginning, middle, or end of the file name. Also, unfortunately, there are spaces in the name of the zipped file and the pdf documents. Currently, we are only copying 4 filenames into separate directories for other people to review and validate.
Below is what I did so far looking around this site:
#Echo off
SETLOCAL
for /R "delims=\\server\contracts\RECEIVED 2017-18 APPLICATION" %%I in
("*.zip") do (
"%ProgramFiles(x86)%\7-Zip\7z.exe" x -y -o"%%~dpnI" "%%~fI"
)
rem setlocal enableextensions disabledelayedexpansion
CLS
::The Input Folder
set "InputFolder=C:\Users\eartha.kitt\Desktop\Test"
::The Output Folders
set "Output1=\\server\contracts\ITEM 1 17-18 CERTS"
set "Output6=\\server\contracts\ITEM 6 SIGNATURES"
set "Output8A=\\server\contracts\ITEM 8A 17-18 CALENDARS"
set "Output8B=\\server\contracts\ITEM 8B 16-17 REVISED CALENDARS"
set "Output8a=\\server\contracts\ITEM 8A 17-18 CALENDARS"
set "Output8b=\\server\contracts\ITEM 8B 16-17 REVISED CALENDARS"
::The extensions to wait
set "extensions=*.pdf"
setlocal EnableDelayedExpansion
:Loop
cls
echo Waiting for file ...
for /f "usebackq delims=|" %%a in ('dir /b /s %InputFolder%\%extensions%
2^>nul') do (
rem for /r %%a in in (%InputFolder%\%extensions% 2^>nul') do (
set "Fichier=%%a"
echo Treating _^> %%a
if "!Fichier:~0,-2!"==" 1" COPY "%%~a" %Output1%
if "!Fichier:~0,-2!"==" 6" COPY "%InputFolder%\~%%a" %Output6%
if "!Fichier:~0,-3!"=="8A" COPY "%InputFolder%\%%a" %Output8A%
if "!Fichier:~0,-3!"=="8B" COPY "%InputFolder%\%%a" %Output8B%
if "!Fichier:~0,-3!"=="8a" COPY "%InputFolder%\%%a" %Output8a%
if "!Fichier:~0,-3!"=="8b" COPY "%InputFolder%\%%a" %Output8b%
::Waiting ~5 seconds
ping localhost -n 6 >nul
)
::Return to the loop
goto:Loop
Of course this doesn't work. Please help!
Well - bravo for the attempt! And so close...
Let's take the first part
for /R "delims=\\server\contracts\RECEIVED 2017-18 APPLICATION" %%I in ("*.zip") do (
"%ProgramFiles(x86)%\7-Zip\7z.exe" x -y -o"%%~dpnI" "%%~fI"
)
What's wrong here is that the delims clause is only usable in for /f. for /r always delivers the entire filename to the metavariable %%I.
On my system I use %server%\u for testing - u is a shared resource on the server assigned to U:\ on server.
for /R "\\%server%\u\contracts\RECEIVED 2017-18 APPLICATION" %%I IN ("*.zip") do (
"%ProgramFiles(x86)%\7-Zip\7z.exe" x -y -o"%%~dpnI" "%%~fI"
worked happily for me - delivering the extracted files to "u:\contracts\RECEIVED 2017-18 APPLICATION"
The second part of your code is examining "C:\Users\eartha.kitt\Desktop\Test" not "\%server%\u\contracts\RECEIVED 2017-18 APPLICATION" - very sensibly assigned to a variablename for easy adjustment.
Here's my modified code:
SET "terminatefilename=stop.txt"
DEL "%terminatefilename%" 2>nul
rem setlocal enableextensions disabledelayedexpansion
CLS
::The Input Folder
set "InputFolder=C:\Users\eartha.kitt\Desktop\Test"
set "InputFolder=\\%server%\u\contracts\RECEIVED 2017-18 APPLICATION"
::The Output Folders
set "Output1=\\%server%\u\contracts\ITEM 1 17-18 CERTS"
set "Output6=\\%server%\u\contracts\ITEM 6 SIGNATURES"
set "Output8A=\\%server%\u\contracts\ITEM 8A 17-18 CALENDARS"
set "Output8B=\\%server%\u\contracts\ITEM 8B 16-17 REVISED CALENDARS"
FOR /f "tokens=1*delims==" %%b IN ('set output') DO MD "%%c" 2>nul
::The extensions to wait
set "extensions=*.pdf"
setlocal EnableDelayedExpansion
:Loop
cls
echo Waiting for file ...
for /f "delims=|" %%a in ('dir /b /s "%InputFolder%\%extensions%" 2^>nul') do (
rem for /r %%a in in (%InputFolder%\%extensions% 2^>nul') do (
SET "copied="
echo Treating _^> %%a
REM OPTION 1 - Key string must be at end-of name part
set "Fichier=%%~Na"
if /i "!Fichier:~0,-2!"==" 1" COPY "%%a" "%Output1%"&SET "copied=Y"
if /i "!Fichier:~0,-2!"==" 6" COPY "%%a" "%Output6%"&SET "copied=Y"
if /i "!Fichier:~0,-3!"==" 8A" COPY "%%a" "%Output8A%"&SET "copied=Y"
if /i "!Fichier:~0,-3!"==" 8B" COPY "%%a" "%Output8B%"&SET "copied=Y"
REM OPTION 2 - Key string may be anywhere in filename
IF NOT DEFINED copied (
echo "%%~na"|FINDSTR /i /L /C:" 8B" >NUL
IF NOT ERRORLEVEL 1 COPY "%%a" "%Output8B%"&SET "copied=Y"
)
IF NOT DEFINED copied (
echo "%%~na"|FINDSTR /i /L /C:" 8A" >NUL
IF NOT ERRORLEVEL 1 COPY "%%a" "%Output8A%"&SET "copied=Y"
)
IF NOT DEFINED copied (
echo "%%~na"|FINDSTR /i /L /C:" 6" >NUL
IF NOT ERRORLEVEL 1 COPY "%%a" "%Output6%"&SET "copied=Y"
)
IF NOT DEFINED copied (
echo "%%~na"|FINDSTR /i /L /C:" 1" >NUL
IF NOT ERRORLEVEL 1 COPY "%%a" "%Output1%"&SET "copied=Y"
)
)
::Waiting ~5 seconds
timeout 6 >NUL
:: Test for exit
IF EXIST "%terminatefilename%" DEL "%terminatefilename%"&GOTO :EOF
::Return to the loop
goto:Loop
First, I set up terminatefilename so that creating this file will terminate the batch (it's an infinite loop by design in your code)
Next, I overrode your inputfolder name to suit my system.
Then the output directories. I adjusted their names to suit my system. Note that batch is largely case-insensitive, so setting Output8A and Output8a is setting the same variable. The only time that batch commands are case-sensitive is the metavariable (loop-control variable) in a for statement.
Then I inserted a line to create the destination directories. This uses a set command to list the variables starting output in the format Output1=\\%server%\u\contracts\ITEM 1 17-18 CERTS (where server will have been resolved). The command reads the output of the set command, uses = as the delimiter and assigns output1 to %%b and \\%server%\u\contracts\ITEM 1 17-18 CERTS to %%c. We want to make sure the directory %%c exists, so we make it with an md command and ignore complaints that it already exists with 2>nul.
Next the for/f. for /f reads each line of (thisfilename) or ("this literal value") or ('the output of this command') but when you need to read a from a file whose name must be double-quoted beacuse it contains spaces, then the syntax is for /f "usebackq"... (idontknow) or ("this filename containing spaces") or ('ive no idea whatever') or (`the output of this command`)
So there's no need to use usebackq -- in fact, it's counterproductive.
The delims=| is optional and could be replaced by delims= as the output of a dir command will never contain | (illegal in a file or directoryname). You do need the delims clause however, as the default delimiters include Space and the default tokens is 1 so only the first string of each line output up to the first space will be assigned to %%a.
Hmm - you've remmed-out a for/r. Sadly, the target directory in the for /r can't be a metavariable.
Next, I've cleared a copied flag saying "so far, this file has not been copied"
Next, set fichier to the name-part only of the filename. Since you are using .pdf as a filter, each name output by the for/f will be a full-filename, ending in .pdf
Next, almost-correct with the battery of if statements. The /i makes the comparison case-insensitive so that it will cope with both 8a and 8A. The strings on both sides of the == must be identical to pass the == test, so you need a 3-character string in the 8 tests.
You've evidently been experimenting with the copy command and trying to feed it with appropriate strings. %%~a strips %%a of any enclosing quotes. %%a won't have enclosing quotes - just the fullfilename, so this does nothing in this instance. %InputFolder%\~%%a concatenates the values from InputFolder,"\~" and %%a - which means "%inputfolder%\~%inputfolder%\filenameandextension of %%a". The last two would be resolved to the same, bar the ~.
Since the entire filename is contained in %%a, all that's needed for the sourcefile is "%%a" - quoted as it will probably contain spaces.
Well - the destination directory (we've already established it with the for /f...%%b) can also contain spaces, so it needs to be quoted, too.
I've then set the flag copied to Y if the line took effect. Actually, it can be set to any non-empty value as the whole object is to interpret whether or not it exists with an if defined statement to bypass any later attempts to copy the same file (remember - copied is cleared for each file)
Now - the second option. This is actually a more powerful detector of the required target strings than is the substring version, and will detect the target string anywhere in the filename.
If you echo the name-part only of the file %%~na into a findstr, then set to findstr to look for the /L literal string /i case-insensitive c:"some literal string" and output ny matches found to nowhere (>nul) then findstr will set errorlevel to 0 if found and 1 otherwise. (the /L is superfluous here, I use it habitually to remind me I'm working with literal strings, not regular expressions)
If errorlevel n will be true if errorlevel is currently n or greater than n, so if the string is found, we do the copy and set the copied flag as before.
I reversed the order of tests because it was easier for me to do using the editor I use.
Now - there's a downside to this approach. It's a double-edged sword. Since the target string is detected wherever it appears in the filename, whatever whatever 10 something something.pdf will pass the test for 1 because Space1 appears in its name.
When the loop has finished, use timeout to wait, redirecting the output to nul to make it pipe down. Note that your delay was inside the for loop - so it would have waited 6 seconds after processing each file, not 6 seconds after processing an entire batch.
Finally, if you create terminatefilename from anothe cmd instance, the batch will exit cleanly and kill terminatefilename for you. Much cleaner than control-c.
A last note: Since you are copying the file, not MOVEing it, it will still exist in the same place presumably after the 6 seconds has elapsed and will be endlessly copied and recopied. You'd probably need to make adjustments to achieve the desired result.
I am writing bat-file to use several executable files (tools that I cannot change) sequentially.
Firs of the tool receive two file names and produce txt file.
Example 1:
Best score for a1_score.txt: 5712
Best score for a2_score.txt: 14696
Example 2:
Best score for data\a1_score.txt: 3023
Best score for data\a2_score.txt: 451
Example 3:
Best score for D:\tmp\a1_score.txt: 234
Best score for D:\tmp\a2_score.txt: 1062
Strings are different because of including full file path. But, fortunately names of file ("a1_score.txt " and "a2_score.txt") will not be changed.
I need two numbers to call next tool, so I tried to write script … but I'm not familiar with the command language and examples I have found in the Internet are not so useful.
Please, help ne to complete the following code:
if exist scores.dat goto scores
echo Cannot read scores
goto BADEND
:scores
for /f "delims=" %%a in ('findstr /c:a1_score.txt /c:a2_score.txt "scores.dat"') do (
set str=%%a
:: some code to create a1_score and a2_score with corresponding values
)
echo %a1_score%
echo %a2_score%
:: some other code
goto END
:BADEND
echo Process was not completed due to errors
:END
pause
Next code snippet could help:
#ECHO OFF >NUL
SETLOCAL enableextensions enabledelayedexpansion
set "scores_dat=%~dp0files\scores32003340.dat" :: my filename value for debugging
if exist "%scores_dat%" goto scores
echo Cannot read scores
goto BADEND
:scores
for /f "tokens=1,2,* delims=:" %%a in ('
findstr /R "a[12]_score.txt" "%scores_dat%"
') do (
if "%%c"=="" (
set str=%%a
set /A "!str:~-12,8!=%%b"
) else (
set str=%%b
set /A "!str:~-12,8!=%%c"
)
)
set a|find /I "score"
echo(%a1_score%
echo(%a2_score%
:: some other code
goto END
:BADEND
echo Process was not completed due to errors
:END
Resources (required reading):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(%~G etc. special page) Command Line arguments (Parameters)
(special page) EnableDelayedExpansion
(for special page) FOR loop summary: all variants
I wrote myself a script based off another one that I found and I'm having trouble figuring out why it's not working.
How it is supposed to work is once a torrent has finished downloading, it runs the script and grabs the Label on the torrent. For testing, I was downloading a song with the label of Music.
When it gets to the point at :copyfile, it won't move it into the correct directory. Instead of moving into F:\Completed Torrents\Music, it just moves into F:\Completed Torrents.
Can someone please point out what I'm missing because I've looked through it thrice already and it's driving me crazy. The script is below.
#echo off
title Liam's torrent-file script
rem Parameter usage: fromdir torrent-name label kind [filename]
rem corresponds to uTorrents flags: %D %N %L %K %F
echo *********************************************
echo Run on %date% at %time%
set fromdir=%1
set name=%2
set label=%3
set kind=%4
set filename=%5
set savepartition="F:\Completed Torrents"
set winrar="C:\Program Files (x86)\WinRAR\WinRAR.exe"
set torrentlog="F:\Torrent Scripts\logs\torrentlog.txt"
set handledlog="F:\Torrent Scripts\logs\handled_torrents.txt"
set errorlog="F:\Torrent Scripts\logs\ErrorLog.txt"
set label_prefix=""
echo Input: %fromdir% %name% %label% %kind% %filename%
rem Check if the label has a sub label by searching for \
if x%label:\=%==x%label% goto skipsublabel
rem Has a sub label so split into prefix and suffix so we can process properly later
echo sub label
for /f "tokens=1,2 delims=\ " %%a in ("%label%") do set label_prefix=%%a&set label_suffix=%%b
rem add the removed quote mark
set label_prefix=%label_prefix%"
set label_suffix="%label_suffix%
echo.prefix : %label_prefix%
echo.suffix : %label_suffix%
goto:startprocess
:skipsublabel
echo Skipped Sub Label
goto:startprocess
:startprocess
echo %date% at %time%: Handling %label% torrent %name% >> %handledlog%
rem Process the label
if %label%=="Movies" goto known
if %label%=="Music" goto known
if %label_prefix%=="TV" goto TV
rem Last resort
rem Double underscores so the folders are easier to spot (listed on top in explorer)
echo Last Resort
set todir=%savepartition%\Unsorted\__%name%
if %kind%=="single" goto copyfile
if %kind%=="multi" goto copyall
GOTO:EOF
:known
echo **Known Download Type - %label%
set todir=%savepartition%\%label%\%name%
echo todir = %todir%
GOTO:process
:TV
echo **Known Download Type - %label%
set todir=%savepartition%\%label_prefix%\%label_suffix%
echo todir = %todir%
GOTO:process
:process
rem If there are rar files in the folder, extract them.
rem If there are mkvs, copy them. Check for rars first in case there is a sample.mkv, then we want the rars
if %kind%=="single" goto copyfile
if exist %fromdir%\*.rar goto extractrar
if exist %fromdir%\*.mkv goto copymkvs
if %kind%=="multi" goto copyall
echo Guess we didnt find anything
GOTO:EOF
:copyall
echo **Type unidentified so copying all
echo Copy all contents of %fromdir% to %todir%
xcopy %fromdir%\*.* %todir% /S /I /Y
GOTO:EOF
:copyfile
rem Copies single file from fromdir to todir
echo Single file so just copying
echo Copy %filename% from %fromdir% to %todir%
xcopy %fromdir%\%filename% %todir%\ /S /Y
GOTO:EOF
:copymkvs
echo Copy all mkvs from %fromdir% and subdirs to %todir%
xcopy %fromdir%\*.mkv %todir% /S /I /Y
GOTO:EOF
:extractrar
echo Extracts all rars in %fromdir% to %todir%.
rem Requires WinRar installed to c:\Program files
if not exist %todir% mkdir %todir%
IF EXIST %fromdir%\subs xcopy %fromdir%\subs %todir% /S /I /Y
IF EXIST %fromdir%\subtitles xcopy %fromdir%\subtitles %todir% /S /I /Y
call %winrar% x %fromdir%\*.rar *.* %todir% -IBCK -ilog"%todir%\RarErrors.log"
IF EXIST %fromdir%\*.nfo xcopy %fromdir%\*.nfo %todir% /S /I /Y
GOTO:EOF
EDIT
Also, for some reason, on line 39 nothing prints to the log. For those who wish to see the code with line numbers: http://hastebin.com/juqokefoxa.dos
A couple of bits for ya:
1) Likely, your script isn't moving the files. Preferences / Directories has an option to move downloads when completed. verify that these settings aren't doing the file moving.
2) uTorrent locks the files on completion so that seeding can continue. To change this behavior, go to Preferences / Advanced and set bt.read_only_on_complete to false
3) you will still be foiled because "Run this program when a torrent finishes" doesn't really do what it says. It runs the program as downloading reaches 100%, but while uTorrent is still either moving the file or seeding. See my bug report here.
A quick summary of the post, just in case that post gets deleted: you have to set the command in "Run this program when a torrent changes state:", add a %S parameter and check that %S == 11
4) Just a tip from my attempt at doing something very similar: when you set the variables from the arguments, add a tilde (%~1 instead of %1). This will strip the quotes off and let us more easily build command lines with the variables later.
You say that the log is not being written to. Try this as a test and see if it writes to the log.
If it doesn't there there is some other fundamental problem.
#echo off
title Liam's torrent-file script
rem Parameter usage: fromdir torrent-name label kind [filename]
rem corresponds to uTorrents flags: %D %N %L %K %F
echo *********************************************
echo Run on %date% at %time%
set "fromdir=%~1"
set "name=%~2"
set "label=%~3"
set "kind=%~4"
set "filename=%~5"
set "savepartition=F:\Completed Torrents"
set "winrar=C:\Program Files (x86)\WinRAR\WinRAR.exe"
set "torrentlog=F:\Torrent Scripts\logs\torrentlog.txt"
set "handledlog=F:\Torrent Scripts\logs\handled_torrents.txt"
set "errorlog=F:\Torrent Scripts\logs\ErrorLog.txt"
set "label_prefix="
set "handledlog=%userprofile%\desktop\handled_torrents.txt"
>> "%handledlog%" echo Input: "%fromdir%" "%name%" "%label%" "%kind%" "%filename%"
>> "%handledlog%" echo %date% at %time%: Handling "%label%" torrent "%name%"
What's a batch script command to touch on a file to update its date and time to the current date and time? (Modified Date)
For example, Joe Blow sends me a text document which he created months ago, when he emails me the document, I want to keep track of how old it is from the day I received it (not when he created it) so I want to update the file's date/time to the current date/time.
I have a batch script to automatically weed out files that haven't been edited within 90 days, so this is troublesome when I receive a particularly older file then all of a sudden it disappears.
And I need it via a batch script as I have hundreds of files to manage, and it's for archiving files.
I can't take all the credit, but I did look through my todo.txt to find it
Microsoft "touch" it's a KB article from like 5 years ago
The jist of it is you use copy /b MYFILENAME +,, where MYFILENAME is your file
This is an expansion on aflat's anwer.
1) Microsoft support provides an explanation and simple touch.bat script.
2) My custom touch.cmd, which expands on the MS script by including "touch /?" help text.
3) My custom midastouch.cmd, which provides several options including recursive operation and date operations.
As aflat wrote, the simple answer is:
copy /b FILENAME +,,
As you might expect, FILENAME can include relative or absolute path and wildcards like *.txt.
1. Microsoft1 support:
The following MS-DOS command updates the date and time stamps of a
file named "EXAMPLE" without altering the contents of the file. This
is similar to the TOUCH utility found in XENIX and in some third-party
MS-DOS toolkits.
COPY /B EXAMPLE +,,
The COPY command can concatenate a file onto an existing file when
used in the form:
COPY FILE1+FILE2
In this example, the contents of FILE2 are appended to FILE1, leaving FILE2 unchanged. When copying in this mode, the COPY command
switches to ASCII mode where the ^Z (0x01A) end-of-file marker is
honored.
Therefore, with the above command, the /b forces the COPY command into
binary mode, the filename is the file to be updated, the + (plus sign)
indicates that a file is to be appended, and the ,, (commas) are
placeholders for the remaining parameters (which are not included in
this example). Because the file to be appended is not specified, the
COPY command will append nothing and only update the time and date
stamps for the file.
The following batch file, TOUCH.BAT, can be used to automate the
process:
#echo off
if %1.==. goto end
if not exist %1 goto end
copy /b %1 +,, > nul
echo %1 touched!
:end
This batch file requires one parameter, the file to be "touched." If the
parameter is not supplied, line 2 will cause the batch file to
exit without doing anything. If the specified file does not exist,
line 3 will cause the batch file to exit also.
2. Touch.cmd
#echo off
:: -----------------------------------------
:: Process input parameter
:: -----------------------------------------
: Help requestes?
if "%1%"=="/?" goto help
if "%1%"=="?" goto help
if "%1%"=="" goto help
:: -----------------------------------------
:: Update Modified Date property to now
:: -----------------------------------------
if not exist %1% goto end
copy /b %1% +,, > nul
echo %1 touched!
goto end
:help
#echo off
echo :: --------------------------------------------------------------
echo :: Touch.cmd Help
echo :: --------------------------------------------------------------
echo.
echo Touch.cmd is batch script to update the Modified Date property
echo of teh specified file to the current
echo date and time.
echo.
echo Syntax: touch filename
echo where,
echo filename is the name of the name of the file to "touch."
echo filename may include a relative o full path.
echo filename may include wild cards like *.txt.
echo.
:end
3. MidasTouch.cmd
#echo off
:: -----------------------------------------
:: Find files older than specified date
:: -----------------------------------------
:: -----------------------------------------
:: Default Values
:: -----------------------------------------
set "default_path=%cd%"
set "default_err_log=%cd%\midastouch_err.log"
set /a default_date=-365
set "open_log=False"
set "recurse=True"
:: -----------------------------------------
:: Process input parameters
:: -----------------------------------------
: Help requestes?
if "%1%"=="/?" goto help
if "%1%"=="?" goto help
if /I "%1%"=="help" goto help
set "dir_in="
set "err_log="
set "dd="
:: Read in commandline arguements.
echo Arguements:
:arguement_loop
if "%1%"=="/p" (
echo Path: %2%
set dir_in=%2%
shift
goto loop_bottom)
if "%1%"=="/l" (
echo Error log: %2%
set err_log=%2%
shift
goto loop_bottom)
if "%1%"=="/-l" (
echo No error log. Output to console.
set err_log=CON
shift
goto loop_bottom)
if "%1%"=="/d" (
echo Date: %2%
set /a dd=%2%
shift
goto loop_bottom)
if "%1%"=="/o" (
echo Open log: True
set "open_log=True"
goto loop_bottom)
if "%1%"=="/-o" (
echo Open log: False
set "open_log=False"
goto loop_bottom)
if "%1%"=="/s" (
echo Recursive: True
set "recurse=True"
goto loop_bottom)
if "%1%"=="/-s" (
echo Recursive: False
set "recurse=False"
goto loop_bottom)
if not "%1%"=="" (
if "%dir_in%"=="" (
echo Path: %1%
set dir_in=%1%
goto loop_bottom)
if "%err_log%"=="" (
echo Error log: %1%
set err_log=%1%
goto loop_bottom)
if "%dd%"=="" (
echo Date: %1%
set /a dd=%1%
goto loop_bottom)
)
:loop_bottom
shift
if not "%1%"=="" goto arguement_loop
if "%dir_in%"=="" (
set dir_in=%default_path%)
if "%err_log%"=="" (
set err_log=%default_err_log%)
if "%dd%"=="" (
set /a dd=%default_date%)
:: -----------------------------------------
:: Execution
:: -----------------------------------------
:: Write header
set "header=Touch_dir.cmd Error Log"
if exist %err_log% (
del /q %err_log%)
#echo %header% >%err_log%
set cmd_str="cmd /c copy /b #path +,,"
:: Update Modified Date property to now
if /I "%recurse%"=="True" (
set cmd_str=forfiles /s /p %dir_in% /d %dd% /c %cmd_str%
) else (
set cmd_str=forfiles /p %dir_in% /d %dd% /c %cmd_str%
)
echo Command: %cmd_str% >>%err_log%
echo Errors: >>%err_log%
echo. >>%err_log%
echo Executing command: %cmd_str%
#echo Updating Modified Date of files older than date: %dd%.
#echo This may take a while. Please be patient...
#echo.
echo.
set cmd_str=%cmd_str% || #echo Failed to update: #path >>%err_log%"
%cmd_str%
:: Results
#echo Error log: %err_log%
if "%open_log%"=="True" (start %err_log%)
goto end
:help
#echo off
echo :: --------------------------------------------------------------
echo :: Touch_dir.cmd Help
echo :: --------------------------------------------------------------
echo.
echo Touch.cmd is batch script to recursively "touch" all files in a
echo folder to update their Modified Date property to the current
echo date and time.
echo.
echo Syntax: touch_dir /d directory /l err_log /m months
echo where,
echo /p path Path containing files with Modified
echo Date values to update to now.
echo (default = current directory).
echo /s (or /-s) Recursive (or not recursive) search
echo (default recursive is %recurse%).
echo /l err_log Error log: list of files not updated
echo (default err_log: midastouch_err.log).
echo /o (or /-o) Open (or do not open) error log after
echo execution (default open_log: %open_log%).
echo /d date Selects files with a last modified date greater
echo than or equal to (+), or less than or equal to
echo (-), the specified date using the
echo "MM/dd/yyyy" format; or selects files with a
echo last modified date greater than or equal to (+)
echo the current date plus "dd" days, or less than or
echo equal to (-) the current date minus "dd" days. A
echo valid "dd" number of days can be any number in
echo the range of 0 - 32768.
echo "+" is taken as default sign if not specified.
echo (default date is: %default_date%).
echo.
:end
Just to add that the same source provide a batch script.
#echo off
goto start
:usage
echo usage: TOUCH.BAT "MYFILENAME"
exit /b 0
:start
if %1.==. goto usage
if not exist %1 goto usage
copy /b %1 +,, > nul
echo %1 touched!
exit /b 0