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
Related
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".
I want to iterate on the files selected by the user when the batch command was called via the context menu of win explorer.
I've searched but haven't been able to find how to do it. So the question is: is it possible? If so, how to do it?
The list of files that get passed in to your script will be stored in the %* parameter. To iterate through them without knowing how many there are, you can use this:
for %%A in (%*) do (
<the rest of your code here, using %%A to represent each file>
)
If your code is too long to be wrapped in a for loop, you can write a second batch file that calls your initial code.
#echo off
for %%A in (%*) do call yourscript.bat %%A
I have 6 different batch scripts that I am running together at the same time. The problem is, it is difficult to differentiate between them in the Windows Task Manager because the process is always just cmd.exe I was wondering if there was a way to change the process name for a batch script to something else so that each script would be more identifiable.
I have done a lot of research on this topic so far, and the only lead that I have is creating a copy of cmd.exe in system32 that has a different name, one of my choosing. The problem is, I am not sure how I would get my bash script to use this new executable with a different name, rather than the default cmd.exe
Requirement: Must use only built in Windows functionality. I do not want to install any other programs if possible.
You can do it with something like the subroutine below. The reason for the first goto is so that you don't fall into the subroutine when you are done. I incorporate another FOR loop to iterate through a list of filenames to check. Let's get this working first.
Your existing bat file goes here
CALL :IsitRunning "SomeFileName"
The rest of your existing bat file goes here
GOTO :eof
:IsitRunning
REM 1=Filename
FOR /F "delims=" %%A in ('WMIC PROCESS WHERE NAME^='CMD.EXE' LIST FULL ^| FINDSTR /I "%~1" ^| FINDSTR /I /V WMIC') DO ECHO(%~1 is running
GOTO :eof
Or you can run this command from a CMD prompt.
wmic process WHERE NAME='cmd.exe' list full | findstr /i "SomeFileName.bat"
You can see command line in Task Manager, turn it on View menu - Choose Columns.
If you want to change process name you have to change the process. So your approach is only way.
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%
I have a list of files in a folder that end with .swf.
I want to change all those files from X.swf to X<some number>.swf.
How can I do that?
This little script will change all *.swf files into the equivalent *_42.swf files.
#setlocal enableextensions enabledelayedexpansion
#echo off
for /f %%a in ('dir /b *.swf') do (
set fspec=%%a
set newfspec=!fspec:~0,-4!_42.swf
echo ren !fspec! !newfspec!
)
endlocal
Actually, as it stands now, it will just echo the commands that it wants to execute. Once you're happy they're correct, you can just remove the echo from that renaming line above.
It works by using for /f to get a list of all SWF files and then using string manipulation to:
remove the last four characters (the.swf extension); then
add a new _42.swf extension onto the end.
And, please, make sure you back them up first :-)
You could use the following one-liner directly from the command prompt:
FOR %F IN (*.swf) DO RENAME "%F" "%~nF123.*"
where 123 stands for your number of choice.
Alternatively you could create a batch file and take advantage of its ability to accept parameters. Use the following script:
#ECHO OFF
SET "suffix=%~1"
FOR %%F IN (*.swf) DO RENAME "%%F" "%%~nF%suffix%.*"
Now if the batch's name is renamer.bat, you can invoke it like this:
renamer.bat 2011
and it will add 2011 to the name of every .swf file in the current directory.
Assuming <X> in your description is supposed to be constant and you don't explicitly require a batch script to solve your problem, you can use Windows Explorer as mentioned in an article by Microsoft titled "Rename a file".
Here's a an extract from said article:
"You can also rename several files at one time, which is useful for grouping related items. To do this, select the files [then press F2]. Type one name, and then each of the files will be saved with the new name and a different sequential number at the end (for example, Renamed File (2), Renamed File (3), and so on)."