First post here :) I am new to creating batch files and have created the below batch file (which took me about 3 weeks to figure out, LOL). Basically, when we get a new assignment we copy the template folder and then rename it the next unused folder name, eg. if the last folder was 15-P0028 the next one would be 15-P0029. the batch works perfectly! But, sometimes we want to add a client name to the end of the folder name, eg. 15-P0029 Brown. I want the batch to pause for user input after renaming the folder the next in sequence so we can enter a client name or just hit enter to insert the new folder without the client name. I think using the set /p would work but I have no idea how to use it properly.
Can anyone help me with this, it would be greatly appreciated.
#echo off
setlocal enableDelayedExpansion
cd /d C:\Users\jbrown\Desktop\Test
set I=2
:NextI
if /I %I% LEQ 999 set II=0%I%
if /I %I% LEQ 99 set II=00%I%
if /I %I% LEQ 9 set II=000%I%
if not exist "15-P!II!" (
xcopy /s /e /i "15-P0000-Template" "15-P!II!"
goto :eof
)
set /a I+=1
if /i %I% LSS 9999 goto NextI
)
yep, you got it, you need the /p "prompt" command. Something like this would work
if not exist "15-P!II!" (
set /p "client_name=OPTIONAL Enter a client name and press <ENTER>: "
xcopy /s /e /i "15-P0000-Template" "15-P!II!!client_name!"
goto :eof
)
we don't need to do any extra processing to check if the user entered a value. If they simply pressed enter client_name should just be an empty string. so adding an empty string onto the end won't affect the name
Related
Currently what I have checks to see if a text file has been modified, if it hasn't then recheck else type out the file contents.
What im attempting to do is after the file contents have been typed out, store a temporary variable with the contents from that file and echo it ONLY when the file is modified.
What im trying to achieve is get the content from a text file, type it to the console and when the file is modified append with new contents from the text file. How do i achieve this?
heres my code
#ECHO OFF &setlocal
set currentDate=%date%
SET File=run.txt
:check
FOR %%f IN (%File%) DO SET filedatetime=%%~tf
IF %filedatetime:~0, 10% == %currentDate% goto same
goto notsame
:same
goto next
:notsame
type %File%
for /f "tokens=*" %%A in (%File%) do (echo %%A)
:next
TIMEOUT /T 1 >nul
goto check
echo.
pause
There is an "Archive attribute". Whenever Windows changes a file, it sets this attribute. We can use this here:
#ECHO OFF &setlocal
SET "File=run.txt"
:check
timeout 1 >nul
attrib "%file%"|findstr /b "A" >nul || goto :check
REM attribute has changed, so the file has.
type "%file%"
attrib -A "%file%" &REM remove the archive attribute
goto :check
If you want to show the new lines only, a tiny little bit more code is necessary (get the number of lines):
#ECHO OFF &setlocal
SET "File=run.txt"
set "lines=0"
:check
timeout 1 >nul
attrib "%file%"|findstr /b "A" >nul || goto :check
more +%lines% "%file%"
attrib -A "%file%" &REM remove the archive attribute
for /f %%a in ('type "%file%"^|find /c /v ""') do set "lines=%%a"
goto :check
The way I am thinking of it depends on who access the data, and what is being added when :/. Someone most certainly will have a better option, but here is my thought if you only want what is newly added to the run.txt.
NOTE set /p will only grab the first line. So assuming there will only be one complete line entered at a time when the file is recreated empty the below should work. As you know your for loop will only grab the last line.
REM Still get first line if there is one
set /p prior_content=<Run.txt
REM Create new run.txt file that will be empty for new content
break>run.txt
REM after your date check of course
:notsame
REM Get new content from the empty run.txt that was created at the beginning
set /p new_content=<Run.txt
REM Echo it to CMD
ECHO %new_content%
REM Output to a log file
(
echo %new_content%
echo.
)>>Run_log.txt
I have done this in the past a bit differently, but I believe this will work depending on your need. If not I am sure someone smarter will come along and correct my errors.
If this is a time sensitive file I would also suggest logging a timestamp of when changes are made. You are doing a timeout of 1 second but are only checking the 10 character date so you will only ever see the change in the file once a day. I am sure you are aware but just in case you are not.
EDIT
As mentioned in the comments I failed to originally include (and remember myself) that set /p contents=<run.txt will only pull the first line of the text file.
I have changed my half brained solution to reflect this fact. :D
I am using a program called "Easy Context Menu" which allows me to create customized context menus when you right click in File Explorer. I wanted to create my own Context Menu item that allows me to copy a file and it's parenting folder structure into another directory, excluding all of the files in the parented folders.
Example:
target file path: C:\the\big\foo\bar.txt
destination path: D:\cow
I want the file 'bar.txt' and it's parenting folders up until 'big' to be copied into the directory 'cow' without the other files in 'big' or 'foo'. The end result should look like:
D:\cow\big\foo\bar.txt
'big' should only contain 'foo' and 'foo' should only contain 'bar.txt'. The program allows me to send the file as a parameter to a file of my choice, in this case a batch file.
I have gotten stuck at the for loop in the ':main" subroutine. It will only print the whole path of the selected file and ignores the delimiter. 'countA' is returned as '1' after the loop and it would have printed the whole path minus drive letter. I do not understand why the for loop is ignoring the delimiter and not separating the path into separate folder names. The reason I am tying to do this is so the user can choose at which point the parented folders should be copied over. This is my first time writing actual code in batch so I still don't completely understand 'setlocal' and a few other things.
I have tried changing the tokens and I am able to choose the individual sections in between the slashes, but I am never able to capture the entire string as separate chunks. I have also changed the delimiter and got the same issue.
#echo off
setlocal
set _target=""
set _dest=""
if not exist %1 goto:error_no_path
set _target=%~pnx1
echo %_target%
goto :dest_selct
:dest_selct
echo select destination folder
pause
set "psCommand="(new-object -COM 'Shell.Application')^
.BrowseForFolder(0,'Please choose destination folder.',0,0).self.path""
for /f "usebackq delims=" %%I in (`powershell %psCommand%`) do set "folder=%%I"
setlocal enabledelayedexpansion
echo You chose %folder%
choice /c ync /n /m "Is this correct? ([Y]es, [N]o, [C]ancel)"
if %ERRORLEVEL% EQU 3 goto:eof
if %ERRORLEVEL% EQU 2 goto:dest_selct
if %ERRORLEVEL% EQU 1 (set _dest="%folder%")&&(goto:main)
:error_no_path
ECHO No file path/name
pause
GOTO:eof
:main
echo main
set _countA=0
echo count starts at %_countA%
for /f "tokens=* delims=\" %%F in ("%_target%") do (
echo token %_countA% is %%F
echo count is %_countA%
set var!_countA!=%%F
set /a countA+=1
)
echo var1: %var1%
echo count is now %countA%
pause
I should have more than one variable at the end, each being the name of a folder that parents the target file and the count should be however many parent folders there are, plus the file itself. What I am actually getting is one variable and it contains the whole target path still.
The for loop does not delimit as you have tokens=*,
which gets all tokens as one token. Leading delimiters are stripped.
Only var0 has a value, not the echoed var1.
To split _target by path segments, use:
for %%F in ("%_target:\=" "%") do echo %%~F
Another issue you have is if you choose n at the choice prompt,
the goto:dest_selct will cause setlocal enabledelayedexpansion
to execute again. Since you are not using endlocal, then the
local environment is recursing without ending. Sometimes endlocal
is implied, so you may not need to use it, though not in this case.
Try this fix:
#echo off
setlocal
set "_target="
set "_dest="
if not exist "%~1" goto:error_no_path
set "_target=%~pnx1"
echo %_target%
goto :dest_selct
:dest_selct
echo select destination folder
pause
set "psCommand="(new-object -COM 'Shell.Application')^
.BrowseForFolder(0,'Please choose destination folder.',0,0).self.path""
for /f "usebackq delims=" %%I in (`powershell %psCommand%`) do set "folder=%%I"
echo You chose %folder%
choice /c ync /n /m "Is this correct? ([Y]es, [N]o, [C]ancel)"
if %ERRORLEVEL% EQU 3 goto:eof
if %ERRORLEVEL% EQU 2 goto:dest_selct
if %ERRORLEVEL% EQU 1 (set "_dest=%folder%") && goto:main
:error_no_path
ECHO No file path\name
pause
GOTO:eof
:main
setlocal enabledelayedexpansion
echo main
set "countA=0"
echo count starts at %countA%
rem Remove leading backslash if exist.
if "%_target:~,1%" == "\" set "_target=%_target:~1%"
rem Split into path segments.
for %%F in ("%_target:\=" "%") do (
echo token !countA! is %%~F
echo count is !countA!
set "var!countA!=%%~F"
set /a countA+=1
)
echo var1: %var1%
rem Echo all variables starting with var and their values.
set var
echo count is now %countA%
endlocal
pause
Adjusted double quoting.
Changed instances of variable name of _countA to countA to match.
set var to show all variables starting with var for debugging.
for loop now spilts on path segments.
Moved setlocal enabledelayedexpansion out of label loop.
Fix 1st argument check if not defined.
Refer to set /? about variable substitution i.e. "%_target:\=" "%", which replaces \ with " ".
I hope someone can help me with my problem.
There is a directory containing folders for every order, e.g.
L:\Med_Department\Orders\
L:\Med_Department\Orders\T0012345_AB100_CustomerA_site2
L:\Med_Department\Orders\T0012346_CD350-CustomerB site1
...
How can I get the full name of a folder by searching for the order number.
When I enter the order number for example:
T0012345
,
I want the script to store
T0012345_AB100_CustomerA_site2
in a variable so I can use it to create the folder for my new project instead of the order number.
The order number is unique and has the format Txxxxxxx . The rest of the folder name can be separated by underscore, blank space or other characters.
If the order number is not found (e.g. order number not entered correctly) the user should enter the order number again.
This is what I achieved so far.
I enter the order number and the script copies a template folder into my projects directory with the order number as folder name.
#Echo off
rem directories
set template= "N:\Documentation\New_folder_OrderNo-Type-Customer-site"
set dirOrder= "L:\Med_Department\Orders\"
SET dirProjects= "Z:\Projects\2016\"
rem input Order No.
echo Please enter the order number?
echo.
set /p OrderNo=OrderNo:
rem target directory
set dirNewProject=%dirProjects%%OrderNo%\
echo %dirnewProject%
pause
rem copy content from template into target directory
xcopy %template% %dirNewProject% /S /E /C /H /O /R /Y /D /V
rem open target directory
explorer %dirNewProject%
;exit
Thanks in advance.
something like this:
#Echo off
rem directories
set template= "N:\Documentation\New_folder_OrderNo-Type-Customer-site"
set dirOrder = "L:\Med_Department\Orders\"
SET dirProjects= "Z:\Projects\2016\"
:again
rem input Order No.
echo Please enter the order number?
echo.
set /p OrderNo=OrderNo:
if not exist "%dirOrder%%OrderNo%\" (
echo order %OrderNo% not found
goto :again
)
:: the rest of the script
:: ...
?
use a for to get the output of a command. Use dir with proper switches to do a wildcard search (Note: with dir wildcards do only work within the very last element of a path).
:again
set /p "OrderNo=OrderNo: "
set "folder=none"
for /f "delims=" %%a in ('dir /s /ad /b %dirOrder%%OrderNo%*') do set folder=%%a
if %folder% == none goto :again
echo found: %folder%
see for /? and dir /? for details
You can simply use for /D against the pattern %OrderNo%*. If there is folder whose name starts with %OrderNo% (there should be one only, if I got it right), dirNewProject is going to hold its path; if there is none, the variable is going to be empty. You can chek if [not] defined dirNewProject afterwards and jump to a :LABEL contitionally:
rem (skipping data entry part of script)
rem directory
set "dirNewProject="
for /D %%I in ("%dirProjects%\%OrderNo%*") do set "dirNewProject=%%I"
if not defined dirNewProject goto :LABEL
rem (skipping file copy part of script)
Example...(Untested)
#Echo Off
SetLocal
Rem directories
(Set template=N:\Documentation\New_folder_OrderNo-Type-Customer-site)
(Set dirOrder=L:\Med_Department\Orders)
(Set dirProjects=Z:\Projects\2016)
Rem exit if above directories do not exist
For %%a In (template dirOrder dirProjects) Do (If Not Exist "%%%%a%%\" Exit/B)
Rem make search dir current
If /I Not "%CD%" Equ "%dirOrder%" PushD %dirOrder%
:AskNum
Rem input Order No.
Echo(
Echo( Please enter the order number?
Echo(
Set/P "OrderNo=OrderNo: "
For /D %%a In ("%OrderNo%*") Do (Set OrderDir=%%~a)
If Not Defined OrderDir (Choice /C /M "Would you like to try again?"
If Errorlevel 2 Exit/B
GoTo :AskNum)
Rem new project directory
(Set dirNewProject=%dirProjects%\%OrderDir%)
Rem copy content from template to new project directory
If Not Exist "%dirNewProject%\" (
RoboCopy "%template%" "%dirNewProject%" /E /Copy:DATSO)
Rem open new project directory
Explorer "%dirNewProject%"
I've got a batch script to utilize a command for an application to create some backups. I've got a loop setup to run through and fetch folder names and then to run the backup operation utilizing those folder names as file names. My loop runs great but my batch script just closes when it is finished. I'd like to escape the loop so I can go back to a choices location I have specified. I've seemingly been unable to escape this loop properly. My code is below:
set /p work=Folder Location:
set /p staging=Location of staging-backup file:
set /p backup=Location to save backup:
#Echo off
md %backup%
setlocal enabledelayedexpansion
set /a $count=1
cd /d %staging%
for /f "delims=" %%a in ('dir "%work%" /b/o') do (
staging-backup "%%a" "%backup%\%%a"
set /a $Count+=1
)
Again, this all runs great (though I can't get it to log properly but thats another battle for later) except I'd love to GOTO CHOICE at the end. When I add it after the closing ) part of the loop, it still closes. When I bring it inside the loop, it closes. Do I need to wrap this loop in an if else to escape it properly?
I tried pulling the code out and pushing it to it's own bat then calling that bat with my original but no change.
:THREE
echo.
echo.
.\Loops.bat
echo.
echo.
GOTO CHOICE
This portion calls it, runs the new bat but still closes the cmd window when it is finished. Any ideas?
#Echo off
setlocal enabledelayedexpansion
:AGAIN
for %%a in (work staging backup) do set "%%a="
set /p "work=Folder Location: "
if not defined work goto :eof
set /p "staging=Location of staging-backup file: "
set /p "backup=Location to save backup: "
md %backup%
set /a $count=1
PUSHD %staging%
for /f "delims=" %%a in ('dir "%work%" /b/A-D') do (
staging-backup "%%a" "%backup%\%%a"
set /a $Count+=1
)
POPD
GOTO AGAIN
Here's a revision.
The first two lines are moved to the top to turn off command-echoing prevent the variables remaining set for each run.
Then insert a label, and clear the variables.
If you reply just Enter to the work prompt, the batch terminates as work will be undefined (set /p leaves the variable unchanged under these circumstances - it does not clear the variable)
PUSHD a directory to switch temporarily to a different directory.
execute staging-backup in that directory. Note that if staging-backup is a batch, then you should use CALL staging-backup... (actually, you could do that with any executable - if it's a batch, you must do it so that cmd knows where to come back to at the end of the destination batch (in this case, staging-backup.bat)
When the for loop is finished, POPD to return to the original directory and loop back to :AGAIN to well - do it all again.
I have scoured the site and have been able to extract code which virtually handles all that I am seeking to achieve. However, I cannot get the last bit to work which is to loop back to the start if I want to re-key another Sheet Number. The code I have:
#Echo Off
cd "C:\temp\CopiedTo"
del *.* /Q
CLS
:start
#Echo Off
Set /P SheetNo=Enter the Sheet Number to Copy:
if exist "C:\temp\%SheetNo%.txt" (Copy "c:\temp\%sheetNo%.txt" "c:\temp\copiedto"
) Else (Echo set choice=
set /p choice="This Sheet Number Is Currently Not in the Directory - Do you wish to Re-Key Again? Press 'y' and enter for Yes: "
if not '%choice%'=='' set choice=%choice:~0,1%
if '%choice%'=='y' goto start
)
You use the %choice% variable inside a block. So you need delayed expansion.
Put a
setlocal enabledelayedexpansion
at the beginning of your script and use !choice! instead of %choice% inside the block.
And: remove the echo before set choice= (probably there for testing)
Here is another way to do it, with a simpler interface.
Note that an automated del *.* on it's own is a dangerous command when the preceding cd command can fail and whatever directory is current can be nuked, so it's always best to specify the folder or do some extra testing to check if the CD failed.
The CD command now has the /d switch to cater for another drive being current.
#Echo Off
cd /d "C:\temp\CopiedTo"
del "C:\temp\CopiedTo\*.*" /Q
CLS
:start
#Echo Off
set "sheetno="
Set /P "SheetNo=Enter the Sheet Number to Copy (press enter to quit): "
if not defined sheetno goto :EOF
if exist "C:\temp\%SheetNo%.txt" (
echo copying "%sheetNo%.txt"
Copy "c:\temp\%sheetNo%.txt" "c:\temp copiedto" >nul
) Else (
echo "Sheet Number "%sheetNo%.txt" Is Currently Not in the Directory
)
goto :start