Passing an argument from one batch file to another - batch-file

I have 2 batch files.
The first one needs an input argument which is a path of a parent folder. It reads the names of all subfolders inside the parent folder and executes the second batch file for each subfolder.
BATCH FILE 1
#echo off
for /d %%Y in (%1/*) do (
set SubfolderNameAndPath=%%Y
call batch2.bat %SubfolderNameAndPath%
)
The second batch file uses as input argument the SubfolderNameAndPath and executes an Evaluate.exe for all the files that exist in each subfolder. It saves the results of the Evaluate.exe to a text file "results" with an extension that carries the name of the subfolder that each time has been accessed. (results_%~n1.txt).
BATCH FILE 2
#echo off
for %%X in (%1/*) do (
echo Evaluate.exe %%X AnotherArgumentHere -o results_%~n1.txt
)
When I run the batch1 (batch1.bat ParentFolderPath) even if it seems to call the batch2.bat, the batch2.bat is not executed. I believe that something goes wrong with the way that I define the input arguments for the batch2.bat but I cannot figure out what it is.
The %SubfolderNameAndPath% does not contain any spaces. Neither the path to the folder does.
I would really appreciate your help on that.

Well, first, when inside a bracketed pair you can't set a variable then access it with the %'s. You must first (before the for loop) setlocal enabledelayedexpansion, then access your variables with the !'s rather than the %'s.
But since you do not do anything with %SubfolderNameAndPath% anyway, you should just eliminate it.
Second, you need to compensate for paths containing spaces, so hopefully my code below will work out for you. To do this, batch uses a special notation for arguments passed to to remove double quotes around them. So, if %1 = "This string", then %~1 = This string. Also, if %1 = This string, then %~1 still = This string. So there is no drawback to using the %~1 notation, unless you want to retain any double quotes.
So, int batch1.bat, we remove any potential quotes surrounding %1, and then place double-quotes around %~1/*, and also double-quote %%Y just in case there are spaces in it.
batch1.bat
#echo off
for /d %%Y in ("%~1/*") do call batch2.bat "%%~Y"
Then we do the same thing for batch2.bat, but more of it.
batch2.bat
#echo off
for %%X in ("%~1/*") do (
echo Evaluate.exe "%%~X" AnotherArgumentHere -o "results_%~n1.txt"
)
EDIT: 2012/09/05 15:21
How's this grab you? Instead of calling a seprate batch:
for /d %%x in (%1\*) do (
for /f "tokens=*" %%y in ( 'dir /b /a:-d "%%~dpnxx"' ) do (
echo Evaluate.exe %%~nxy AnotherArgumentHere -o "results_%%~nxx.txt"
)
)
(The above can be put all on one line, just remove the brackets.)
I'm assuming the output is:
Evaluate.exe <file_name> AnotherArgumentHere -o "results_<directory_name>.txt"

Related

How to clean-up file paths (back/forward slashes) provided as arguments in a .bat script to avoid syntax errors

I have a simple .bat script which renames all files in a folder using ren. The input argument is a path to a folder containing the files to be renamed. The script sometimes returns syntax errors which we've traced to the fact that sometimes the input path has forward slashes, backslashes, or a mix of both (and sometimes starts with a double forward slash). We would like to make this script more robust by allowing it to accept any of these types of paths, and cleaning up the path as part of the .bat script before calling the ren command.
So my question is: is there a (set of) command(s) I can apply to the file path argument (%1 in the example below) before calling the ren function that will correct all forward/backslashes to be consistent and avoid syntax errors? I don't have much experience with .bat scripts, so any code examples would be helpful.
#echo off
setlocal ENABLEDELAYEDEXPANSION
for %%F in (%1*.nc) do (
for /F "tokens=1-8 delims=_" %%a in ("%%~nF") do (
ren "%%F" "%%a_%%b_%%c_%%d_%%e_%%g_%%f_%%h.nc"
)
)
UPDATE: In the end, only the last suggestion by Magoo was needed, because changing %1 to "%~f1" fixed the slash issues. I also had to add %~f1\ to the first argument of the ren command because otherwise it was somehow looking in the wrong folder (the first for found the files ok, but the ren command was looking in the wrong folder.
#echo off
setlocal ENABLEDELAYEDEXPANSION
for /F "delims=" %%F in ('dir /b /a-d "%~f1\*.nc"') do (
for /F "tokens=1-8 delims=_" %%a in ("%%~nF") do (
ren "%~f1\%%~nF.nc" "%%a_%%b_%%c_%%d_%%e_%%g_%%f_%%h.nc"
)
)
set "corrected=%~1"
set "corrected=%corrected:/=\%"
Then use %corrected% in place of %1 AND quote the filename thus:
for %%F in ("%corrected%*.nc") do (
If %1 is always a directory-name, then add
if "%corrected:~-1%" neq "\" set "corrected=%corrected%\"
as a third set line before the for line.
The first set assigns the value of %1 to a variable corrected - the ~ removes any enclosing quotes.
The second set changes all strings matching that between the : and = into that between the = and % in the variable given and assigns to the first-mentioned variable (can be the same variable, as in this case)
The third set, if used, checks that the last character is \ and if it is not, appends a \.
The quoting of the filename-string allows there to be spaces in the path/filename and is harmless if there are no spaces.
To avoid attempting to rename a file twice, instead of
for %%F in ("%corrected%*.nc") do (
use
for /F "delims=" %%F in ('dir /b /a-d "%corrected%*.nc"') do (
This builds a list of filenames in memory, then processes that list.

How to delete all hardlinks of multiple files on windows 10?

I create a lot of hardlinks every week. When time comes to clean them, I find myself using the "DeleteAllHardlinks.bat" for ln (https://schinagl.priv.at/nt/ln/ln.html) but I have to drag and drop everyfile one after the other.
I would love to find a way to just select 100 files and drop them on the .bat, wait a while and find all those files and hardlinks deleted for good. Is there anyway to change the .bat file to allow this? (or maybe any other different method to acomplish the same?)
#echo off
REM
REM Check for commandline args
REM
if "[%~1]" == "[]" goto error
set LN=ln.exe
REM
REM List hardlink sibblings and delete all siblings
REM
for /f "delims=" %%a in ('#%LN% --list "%~1"') do (
del /f "%%a"
)
goto ausmausraus
:error
echo DeleteAllHardlinks: Argument is missing. Usage DeleteAllHardlinks ^<filename^>
echo e.g. DeleteAllHardlinks c:\data\myfile.txt
:ausmausraus
echo on
Thanks in advance!
Big thanks to Mofi!
The batch file could be very easily modified to support not just first argument, but all file name argument strings passed to the batch file by using one more for loop and %* as explained by call /?, i.e. use as replacement for the existing for loop:
for %%I in (%*) do for /F "delims=" %%J in ('ln.exe --list "%%~I" 2^>nul') do del /F "%%~J"
But the application starting the batch file has to pass each file name enclosed in double quotes to work properly.
Just using the for as offered in the comment solved the issue perfectly.

how to properly pass file with spaces as parameter using call

I have written a small script to read all the files in the given directory and check for occurrence of a string.
This seems to work until I call %1 in the called .bat.
The problem I am facing is that when I use the call function the new .bat file that is executed doesn't have the full name of the parameter given.
The script
NET USE O: "\\MyNetworkDrive\MySelectedFolder"
IF NOT "%~1"=="" GOTO ADDV
SET VAR=
FOR /F "tokens=* USEBACKQ" %%F IN (`DIR *.* /s/b/A:-d-h`) DO FIND /i "stringToFind" "%%F" && CALL %0 %%F
SET VAR
GOTO END
:ADDV
SET VAR=%VAR%!%1
:END
ECHO %VAR% > search.txt
pause
As you can see the script checks if %1 not equals empty string.
Now in the for do loop I check for a string in the file and if the file has one it calls the same script with the file path as parameter (the correct file path e.g. O:\MyNetworkDrive\MySelectedFolder\My File.xls)
however when I call the %1 in the called .bat it equals O:\MyNetworkDrive\MySelectedFolder\My.
What is causing the %1 variable to not contain the correct file path?
How can I solve this?
All that I could find on the internet about this is about quoting the path with double quotes and using %~1 to negate the quotes in the variable, which I have used correctly as far as I know.

Trying to write a calling batch file but keep getting "cannot find" error

I am trying to write a batch file that calls another which replaces two files in a directory. Here is my code:
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
call C:\%mmcIpath%\spc_we_replace_CED+CEDU.bat
Whenever I set the temporary environment variable, it says the directory cannot be found.
--ADDITIONAL INFO--
I run a Minecraft launcher called MultiMC5; it has a feature which runs commands - but only one command, for some reason. So I wanted it to call a batch file to run multiple commands.
My main batch file is in "C:...\MultiMC\instances", but I want the program to be able to call it. It cannot, as it works within a subdirectory called "CED (210 mods-)". So I placed another batch in the subdirectory to call the main one (I wanted to do the same for a second subdirectory called "CEDU (300+ mods-)"). I got this error: "The system cannot find the path specified.". It happened when I set the path.
I'm using Windows 8.1 and have searched for tips on how to use wildcards and on how to use FOR loops, but none of the wildcard methods have worked for me and I cannot understand FOR loops at all. I have also tried to remove and add things like quotation marks in an attempt to fix it, but that didn't work either.
My question:
Is the set command compatible with wildcards and if so, how do I get this to work?
It looks like your problem is that the main batch file can be on any drive and you want to call other batch files with a path relative to the location of main batch file. Is that correct?
You can get the drive with %~d0, path with %~p0 and drive + path with %~dp0. See the example below and execute this little batch file stored in several different directories:
#echo off
echo Batch is stored on drive %~d0
echo in the directory %~p0
echo resulting in path %~dp0
So you can use argument 0 referenced by %0 containing always name of batch file with full path using the syntax above explained in help of command FOR displayed with entering for /?in a command prompt window to call the other batch files with a path depending on path of the main batch file.
Now what we have here is a classic XY problem - being asked about a solution, not the underlying issue.
Here's a possible resolution:
#ECHO OFF
SETLOCAL
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
set "mmcIpath=U:\\.*\\mmc-stable-win32\\MultiMC\\instances"
SET "targetbat=spc_we_replace.bat"
FOR /f "delims=" %%a IN (
'dir /b/s /ad "%mmcIpath:~0,3%"^|findstr /e /i /r /c:"%mmcIpath%" '
) DO (
IF EXIST "%%a\%targetbat%" (
ECHO CALL "%%a\%targetbat%"
ECHO GOTO nextstep
)
)
:nextstep
GOTO :EOF
I've left the original setting of mmcIpath in place, and replaced it with a form to suit my system.
The approach is to execute a dir/s/b/ad command (directory, basic format, with subdirectories, directory names only) and filter it using findstr. I chose switches /i (case-insensitive) /e (must end with string) /r regular-expression /c: (following is one string to be matched).
The regex is constructed according to findstr's rules - \ needs to be doubled if it is to be used as a literal; .* means 'any number of any character'
This should provide a list of literal directory names which get through the filter. Look in the directory found for the filename, call the target file if found. The required CALL commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO CALL to CALL to actually execute the files.
The following ECHO GOTO is there to show that the loop can be broken after finding the first target file, if desired. You havent't indicated whether you want to run only the first or run all of the targets found.
Here's my test source. I use U: for testing data. Your system would likely be different.
#ECHO OFF
SETLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION
set "mmcIpath=\mmc-stable-win32\MultiMC\instances"
FOR /l %%a IN (1,1,4) DO MD u:\%%a%mmcIpath% 2>nul
FOR /l %%a IN (2,2,4) DO COPY NUL u:\%%a%mmcIpath%\spc_we_replace.bat 2>NUL >nul
ENDLOCAL
ENDLOCAL
#ECHO OFF
SETLOCAL
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
set "mmcIpath=U:\\.*\\mmc-stable-win32\\MultiMC\\instances"
SET "targetbat=spc_we_replace.bat"
FOR /f "delims=" %%a IN (
'dir /b/s /ad "%mmcIpath:~0,3%"^|findstr /e /i /r /c:"%mmcIpath%" '
) DO (
IF EXIST "%%a\%targetbat%" (
ECHO CALL "%%a\%targetbat%"
ECHO GOTO nextstep
)
)
:nextstep
GOTO :EOF
Note that the first section is merely establishing u:\1\mmc-stable-win32\MultiMC\instances to u:\4\mmc-stable-win32\MultiMC\instances then creating a dummy file spc_we_replace.bat in u:\2\mmc-stable-win32\MultiMC\instances and u:\4\mmc-stable-win32\MultiMC\instances.
The string assigned to mmcIath in the second section is according to findstr's syntax rules - each \ is doubled, .* means "any number of any character". You would have to modify that string to suit your system. Note that "%mmcIpath:~0,3%" gratuitously takes the first 3 characters from the string. In my case, that would be U:\. YMMV

Batch renaming last few characters of files

I'm trying to create a batch file that would rename a bunch of files in a folder. These files would have a naming of something like: blah(lol).txt. There will always be a four letters, followed by an open bracket, three letters, and finally a close bracket.
I want the batch file to remove the bracketed part of the name of the file, ie. rename the file without the bracketed part.
for %%i IN (*.txt) DO (set name=%%~ni
set name2=%name:~1,4%
ren %%i %name2%)
Why doesn't this work?
Magoo provided an explanation as to why your script failed, as well as a working script.
But in your case, there is no need for a script. A simple REN command is all that is needed:
ren "????(???).txt" "????.*"
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "tokens=1,2,3delims=()" %%a IN (
'dir /b /a-d "%sourcedir%\*(*).*" '
) DO ECHO REN "%sourcedir%\%%a(%%b)%%c" %%a%%b%%c
GOTO :EOF
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.
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
simple but works from the folder with the files to be renamed.
#echo off
title Rename Bat
echo This bat must be in the folder that
echo contains the files to be renamed.
:begin
echo Enter File Name
set /p old=
echo Enter New Name
set /p new=
ren "%old%" "%new%"
echo File Renamed
ping -n 3 127.0.0.1 >NUL
goto begin
a much simpler approach ... try a for loop that cycles through all files in your folder
I'm going to use lol as an example of three letter word inside brackets as stated in your question
#echo off
for %%a in (*) do (
rename "%%a" "%%a(lol).exe"
)
to use this batch file you have to place it in the folder containing the files you wanna rename

Resources