Windows cmd suggested input - windows

I am attempting to write a .bat file that prompts the user for a file path before continuing. However, this is a script that I plan on running repeatedly on the same file, so it would save me a lot of time to not have to re-enter that path every time. I plan on saving the path to another file each time it's run. What I'm hoping i can do then is, when the prompt comes up, have the previous path pre-entered. That way I could either just hit enter, or backspace and change it to a new path. How would I go about pre-entering the text? Is it possible? Any feedback or suggestions are welcome.

for /f "usebackq delims=" %%a in ("c:\path to\wherever\your\file.is") do set "filepath=%%a"
set /p "filepath=Select path or just [Enter] for %filepath%"
echo select path was "%filepath%"
>"c:\path to\wherever\your\file.is" echo %filepath%
The point is that set /p leaves the target variable unmolested if the Enter key alone is used.

#ECHO OFF
IF EXIST %~dpn0.save.cmd (CALL %~dpn0.save.cmd)
SET /p "savedpath=Please specify file path or press Enter for default [%savedpath%] : "
ECHO SET savedpath=%savedpath%> %~dpn0.save.cmd
The beauty of this approach is that, if elsewhere in the script you decide that the preserved value should be forgotten, you just delete the .save.cmd file.
Years ago - when I used to work in command scripts everyday - we had examples where these types of values would come from a different section of the same script file, and the preserved values would simply be written back to the same file; however, I can't recall the details, and this separate-file approach will do the trick.

Related

Run Batch Script Across Subfolders (Recursively)

I regularly have to rename hundreds of files across a subfolder structure. I have been creating a batch file consisting of all my rename commands, and manually pasting this into each subfolder to execute one subfolder at a time. I'd like to revise the batch script so that it executes against all subfolders in one fell swoop, run from the parent directory just once.
My renaming is very manual, and so I need to create a discrete entry for each file. For example, here are three lines:
REN STWP01_00669087* BCBSRI-01849351*
REN BCBSRI-01849357* 2011-12-19_BCBSRI-01849357*
REN STWP01_00669094* BCBSRI-01849369*
I've experimented with the FOR /R command, including trying a separate batch file that calls my renaming batch file (via the CALL command). No luck.
I have to assume that this is simple, but I'm a batch novice, so any help would be appreciated.
Thanks!
#Magoo,
Thanks so much for your response. Your approach is going to be far more efficient than my own so far.
A couple of questions. Please bear with me as I am a total novice with batch commands.
Here's what I did: I saved your code to a .BAT file ("RRename.bat"), modified my filenames as per your instructions and saved those to a text file ("Filenames.txt"), and then run this command from the command line: {RRename.bat Filenames.txt}.
The resulting command windows confirm correct renaming. And so I removed the ECHO and PAUSE commands and re-ran. No luck. Just a bunch of Command windows confirming the directory.
Ideally I'd love to save this as a .BAT file and simply drop this in the top-level directory, together with the data file that contains the old names and new names of the files. And so, a double-click of "RRename.bat" will parse the content of "Filenames.txt" and work its way through all subfolders, renaming wherever matches are encountered. Boom.
To that end:
1. How do I make it so {SET "sourcedir=} indicates the current directory (i.e. the directory in which the batch file is located)? This way I wouldn't ever need to change this variable. (I should note that I am running this script on a network location, which requires me to map the drive, resulting in a different drive letter every time.)
2. How do I hard-code the name of the data file into the script itself? My goal is an easily replicated process minimizing user input (save for the content of the data file).
3. How do I stop the individual command windows from appearing? I'll be renaming thousands of files at a time and don't want to see thousands fo corresponding command windows.
Thank you!
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
:: read parameters
SET "filename1=%~1"
SET "filename2=%~2"
IF DEFINED filename2 GOTO name
IF NOT DEFINED filename1 GOTO :EOF
:: 1 parameter - must be filename
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO START /min "ren %%a" "%~f0" %%a
GOTO :eof
:: we have 2 parameters so rename pattern 1 to pattern 2
:name
FOR /r "%sourcedir%" %%a IN ("%filename1%*") DO CALL :process "%%a"
PAUSE
GOTO :EOF
:: Process the filenames and actually do the rename
:process
:: Name of file to be changed - name and extension of %1
SET "changeme=%~nx1"
:: REPLACE up-to-from-pattern with nothing = remainder of name/extension
CALL SET "endpart=%%changeme:*%filename1%=%%"
:: and RENAME...
ECHO(REN "%~1" "%filename2%%endpart%"
GOTO :eof
You would need to change the setting of sourcedir to suit your circumstances.
Revised data file
STWP01_00669087 BCBSRI-01849351
BCBSRI-01849357 2011-12-19_BCBSRI-01849357
STWP01_00669094 BCBSRI-01849369
Aimed at processing the above file, renaming files starting (column1 entries) to start (column2 entries.)
Method:
Run the batch as
batchname filename
This will execute the batch, processing filename
How:
having set the directory name to start processing from, set filename1&2 to the values of the parameters supplied.
If only 1 is supplied, it is the filename, so process it line-by-line and START a new process /min minimised "with the window name in the first set of quotes" and execute this same batch with the data from each line of the file in turn, then finish by going to :eof (end-of-file - built-in to CMD)
The sub-processes all have 2 parameters (eg BCBSRI-01849357 2011-12-19_BCBSRI-01849357) so processing passes to :name. This runs a for /r loop, from the specified source directory, with the name specified from the first column+* and executes :process passing the filenames found as parameter 1.
:process sets changeme to the filename in question, calculates endpart by removing the string filename1 from changeme which will deliver the er, end part.
Then simply rename the supplied filename to the replacement name+that endpart calculated.
The required REN commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(REN to REN to actually rename the files.
The PAUSE is just to allow the proposed changes to be seen. Once the process has been verified, change the PAUSE to EXIT.
AAMOI, running
*batchname* STWP01_00669094 BCBSRI-01849369
for instance, would execute the recursive-rename from STWP01_00669094* to BCBSRI-01849369*
Sadly, "No luck" is meaningless.
I have made a minor, but significant change to the instructions. The PAUSE should be changed to an EXIT after testing.
After testing, the ECHO(... line should become
REN "%~1" "%filename2%%endpart%"
which actually executes the rename. If you've just deleted the line, it would explain the no-visible-result.
Having restored the original code and verified against a small representative dummy subtree, change the echo(... line and test again. The filenames should change. If not, something is dreadfully wrong. Needless to say, this works perfectly happily for me...
Then try again with the PAUSE changed to EXIT. This time, the windows generated will appear on the taskbar and then disappear when the rename for that line of the input file has finished. This will happen once for BCBSRI-01849357 rentwo for instance - not once for each individual file rename occurring.
To hard-code the filename, remove the line
IF NOT DEFINED filename1 GOTO :EOF
and replace
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO START /min "ren %%a" "%~f0" %%a
with
FOR /f "usebackqdelims=" %%a IN ("YOURFILENAMEHERE") DO START /min "ren %%a" "%~f0" %%a
For the "run from here" command, change
SET "sourcedir=U:\sourcedir"
to
SET "sourcedir=."
. means "the current directory"
If you place thisbatchfilename.bat into any directory on your PATH then you can run the routine simply by executing thisbatchfilename.
You can display your path by typing
path
at the prompt. PATH is the sequence of directories searched by windows to find an executable if it isn't found in the current directory. To chane path, google "change path windows" - experienced batchers create a separate directory on the path for batch files. Sometimes, they name the directory "Belfry".

How to Increment a FileName in batch? (Part2)

I already tried the answer given by Mofi in my last question regarding this topic. But I changed the base name and it does not seem to work by now. If you want to see the previous question:How do I increment a filename in batch? What is wrong with this new code? It does not make a new file it just overwrites the previous made file.
:MainProcessNew
cd /D "%USERPROFILE%\Desktop"
for /F %%G in (*.json) do (
set "FileName=%%G"
set "BaseName=Device"
set "FileNumber=0"
)
:FileNameLoop
set /A FileNumber+=1
if exist "%BaseName%%FileNumber%.json" (
goto FileNameLoop
)
echo.>"%USERPROFILE%\Desktop\%BaseName%%FileNumber%.json"
I'm quite sure the batch code in question is not complete or reduced to a script code not really suitable to reproduce the problem because with Device.json existing in folder Desktop and no other Device*.json file existing, the empty line is first written to Device1.json. A file with name Device.json is never overwritten by the batch code in question because variable FileNumber has always at least the value 1.
Well, the FOR option /F is most likely wrong here as I suppose the FOR loop should search for *.json files as done without /F. Using a wildcard pattern like *.json together with option/F results in error message:
The system cannot find the file *.json.
Run in a command prompt window for /? or help for for help on syntax of this command.
It is completely unclear what is the purpose of the FOR loop because the FileName variable is not used at all. This variable should perhaps hold the name of last found *.json if there was any *.json file found at all. But that also does not make sense if not further used anywhere.
It is also unclear why BaseName and FileNumber are defined inside the loop and not outside.
In the complete batch code the label FileNameLoop is perhaps the beginning of a subroutine. But in the reduced batch code in question there is no call :FileNameLoop "%%G" which I would expect in this case.
So the question is hard to answer as it is unclear what is really the problem with posted batch code.
:MainProcessNew
cd /D "%USERPROFILE%\Desktop"
rem Useless FOR loop without /F commented out.
rem for %%G in (*.json) do set "FileName=%%G"
set "BaseName=Device"
set "FileNumber="
rem Skip searching for files with a file number
rem after Device if there is no Device.json file.
if not exist "%BaseName%.json" goto CreateFile
rem Otherwise keep Device.json as is and search for Device1.json,
rem Device2.json, ... until a Device*.json file with current number
rem is not found and use this number for next Device*.json file.
set "FileNumber=0"
:FileNameLoop
set /A FileNumber+=1
if exist "%BaseName%%FileNumber%.json" goto FileNameLoop
:CreateFile
rem Note: FileNumber is replaced in the line below by an empty
rem string if there is no Device.json in desktop folder.
echo.>"%USERPROFILE%\Desktop\%BaseName%%FileNumber%.json"
Hint: For debugging a batch file
comment out or remove all #echo off or echo off in the batch file or change off to on,
open a command prompt window,
enter "Path to batch file\BachFileName.bat" and press RETURN.
Now it can be seen in the command prompt window each line executed by Windows command processor after preprocessing each line and each command block which means after replacing all %VariableName% by the current value of the variable in current line or entire command block.
And error messages can be also seen as the command prompt window remains open after processing batch file stopped, except it contains the command exit without option /B which always terminates the current command process.

Check Batch File Location before Executing

I have wrote a batch file to Backup User Profile, but I would like to make it idiot proof.
A few times I have actually left the batch file on my desktop and run it on my own profile and as the batch file contains a robocopy command to copy the Desktop folder, it creates an infinite loop of duplicate folder inside one and other, which are difficult to get rid off due to the 256 character limit.
I am trying to get the batch file to check its own location is not within the user profile before executing.
I was messing around last night with the IF command and this is what i came up with:
#ECHO off
SET /P %UserName%=Enter Username:
IF "%~dp0"=="C:\Users\%UserName%\NUL" (
GOTO ERROR
) ELSE (
GOTO PROFILEBACKUP
)
:PROFILEBACKUP
REM To Be replaced by Profile Backup Script
ECHO Correct Location
:ERROR
ECHO Move ProfileBackup.CMD to another location
But the only output I get is:
Enter Username: smithsl
Correct Location
Move ProfileBackup.CMD to another location
Any help would be appreciated
Here is a suggestion for a batch code checking if location of batch file is somewhere in user's profile directory tree.
#echo off
setlocal EnableDelayedExpansion
set "BatchPath=%~dp0"
:EnterName
rem Define as default name of current user.
set "NameOfUser=%UserName%"
set /P "NameOfUser=Enter user name (default: %NameOfUser%): "
rem Remove double quotes from entered string.
set "NameOfUser=!NameOfUser:"=!"
rem Were something different than just double quotes entered?
if "%NameOfUser%"=="" goto EnterName
rem Remove also angle brackets and exclamation marks.
set "NameOfUser=!NameOfUser:<=!"
if "%NameOfUser%"=="" goto EnterName
set "NameOfUser=!NameOfUser:>=!"
if "%NameOfUser%"=="" goto EnterName
set "NameOfUser=%NameOfUser:!=%"
if "%NameOfUser%"=="" goto EnterName
rem Starts the path of the batch file with C:\Users\entered user name?
if not "!BatchPath:C:\Users\%NameOfUser%=!" == "%BatchPath%" goto LocationError
rem To be replaced by profile backup script
echo Correct Location
endlocal
goto :EOF
:LocationError
echo Move %~nx0 to another location.
endlocal
goto :EOF
Although some tests are made for checking invalid user input, it is still not idiot proof as this is nearly impossible when a user can enter something.
The mistake you made was assigning entered value to %UserName% which means if your user account name is for example Scott, the entered string is assigned to an environment variable with name Scott and not to environment variable with name UserName. It is of course no good idea to overwrite the predefined UserName environment variable value by a batch script.
Open a command prompt window, execute there set /? and read the help printed into the console window to understand the string replacements used in this batch code using additionally delayed environment variable expansion.

how to send each iteration of a loop in a batch script to a new cmd window and continue with loop

Disclaimer: I'm an engineer not a programmer, so while I do have technical knowledge, please bear with me if I am using the wrong terminology or asking the wrong questions.
I am trying to write a windows batch script that will allow me to submit multiple finite element simulations as a batch with all of the same settings. I currently have a script that works after a fashion, but it is not as efficient as I would like. My current script steps through the directories and runs the simulation in the command window before moving on to the next directory and repeating the loop. This script can be seen below:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
title BEST FRM Runs batch submission
echo This script will step through the run# directories and run the blast.k file in each run# folder. The .cmd file needs to be placed in the "FRMRuns" directory. You may need to change the reference to the LSDYNA solver if the version has changed.
SET /P ANSWER=Do you want to continue (y/n)?
if /i {%ANSWER%}=={y} (goto :yes)
if /i {%ANSWER%}=={n} (goto :no)
:yes
SET /P i=Enter input file name (e.g blast.k)
SET /P n=Enter number of CPUs (e.g. 2)
SET /P m=Enter memory (e.g 500m)
FOR /D %%D IN (run*) DO (
echo %%D
cd %%D
set lstc_license=network
set lstc_license_server=###.##.##.##
::the solver reference may need to be changed as we move on to new versions
c:\LSDYNA\program\ls971_s_R5.1.1_winx64_p.exe i=%i% ncpu=%n% memory=%m%
cd ..
)
exit /b
:no
exit /b
Our network licensing for LSDYNA allows for queuing of jobs, so ideally I would like to run through the entire loop and have the jobs run simultaneously rather than run one after another. I think this would be possible if I could send each iteration of the loop to a new command window and have it execute independently while the loop in batch script continues.
I'm not sure if I am searching for the wrong things, or if this is a unique request, but I have not been able to find anything that really helps with what I am trying to do. I have tried various things using start /b cmd /k, but I have not been able to pass the loop commands to the new window and have the loop continue in the original window. I have managed to get the new window to open, but not to actually execute any commands, and the code does not continue until the new window is closed.
I would appreciate any suggestions that you might have for how to accomplish my goal.
Thank you!
This starts each command in it's own process, with the start "" at the beginning.
start "" c:\LSDYNA\program\ls971_s_R5.1.1_winx64_p.exe i=%i% ncpu=%n% memory=%m%

pipe multiple files into a single batch file (using explorer highlight)

I can already get a batch file to run when a user right clicks on a file type. How can I make it so that only one instance runs per highlighted group and gets all the files as arguments.
Currently it runs single instance per file when a user "shift clicks"
there is most likely a better way to word this... you can see why I had trouble googling it.
thanks
Normally a file association multi-selection invocation will start several instances of a program and the program itself would have to deal with it on its own (Or with the help of DDE or IDropTarget)
It is going to be very hard to implement this in a batch file, this example should get you started:
#echo off
setlocal ENABLEEXTENSIONS
set guid=e786496d-1b2e-4a49-87b7-eb325c8cc64d
set id=%RANDOM%
FOR /F "tokens=1,2,3 delims=.,:/\ " %%A IN ("%TIME%") DO SET id=%id%%%A%%B%%C
set sizeprev=0
>>"%temp%\%guid%.lock" echo %id%
>>"%temp%\%guid%.list" echo %~1
:waitmore
>nul ping -n 3 localhost
FOR %%A IN (%temp%\%guid%.list) DO set sizenow=%%~zA
if not "%sizeprev%"=="%sizenow%" (
set sizeprev=%sizenow%
goto waitmore
)
FOR /F %%A IN (%temp%\%guid%.lock) DO (
if not "%%A"=="%id%" goto :EOF
FOR /F "tokens=*" %%B IN (%temp%\%guid%.list) DO (
echo.FILE=%%B
)
del "%temp%\%guid%.list"
del "%temp%\%guid%.lock"
pause
)
While this works, it is a horrible horrible hack and will fail badly if you don't wait for the first set of files to be parsed before starting a new operation on another set of files.
If you create a batch file and place it on your desktop, then you can select multiple files and drop them on that batch file. They will get passed as multiple parameters to the file.
For example, assume you put dropped.bat on your desktop, and it looks like this:
#echo off
echo %*
pause
Now assuming you had three files x, y and z, if you multiple-selected them and dropped them on dropped.bat, you'd see a command window come up with this text in it:
C:\Users\alavinio\Desktop\x C:\Users\alavinio\Desktop\y C:\Users\alavinio\Desktop\z
Press any key to continue . . .
That's the closest you can get. The right-click-and-Open semantics expect to start a new executable for each selected item, and typically those executables check for another instance of themselves, and if they see one, send the parameter over there to that existing process, and terminate themselves. You can actually watch that happen with Task Manager or Process Explorer.
Late to the party but here is my 2 cents. I had the same problem when trying to customise the behaviour of a 'Move to Dropbox Folder...' context menu command. I needed every file selected to be piped to a batch file to handle the processing in one instance.
After some digging I found Context Menu Launcher.
Simple enough to use. I popped singleinstance.exe in C:\Windows\system32 and created and ran a .reg file similar to below.
Windows Registry Editor Version 5.00
; Documents
[HKEY_CLASSES_ROOT\SystemFileAssociations\document\Shell\Dropbox]
#="Move to Dropbox Folder"
"Icon"="%SystemRoot%//system32//imageres.dll,-112"
"MultiSelectModel"="Player"
[HKEY_CLASSES_ROOT\SystemFileAssociations\document\Shell\Dropbox\command]
#="singleinstance.exe \"%1\" \"C:\\Move to Dropbox Folder.bat\" $files --si-timeout 400"
The way it works seems to have been imposed on you by the shell, and there doesn't seem to be an easy way to solve this.
Some application would add its own menu item that would allow the app to be invoked differently (i.e. just once for the group) from how it is done generally (repeatedly for every selected item), while another one would employ the API to check its own presence and would redirect the 'open' request to its already running copy.
Batch files aren't meant for either of these. You would probably need a different tool. Even if you would like the main job to be done by the batch file, you'd still need a way to call the batch file for processing of the item list.
I'm guessing you have a group of highlighted files and you want to run some program for each file.
#echo off
for %%A in (%*) do echo %%A
pause

Resources