Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a unique temporary file path in command prompt without external tools? [duplicate]

Tags:

batch-file

cmd

I am trying to create the path to a temporary file to be used in a batch file.

There are the environment variables %TEMP% and %TMP% to get the temporary directory for the current user. But how to build a file name that does surely not yet exist?

Of course I can use the built-in variable %RANDOM% and create something like bat~%RANDOM%.tmp, but this method does not ensure that the file is currently inexistent (or that it will be created coincidentally by another application, before I first create it on disk and write to it) -- although this all is very unlikely.

I know I could just reduce the probability of such collisions by appending also %DATE%/%TIME%, or by just adding multiple %RANDOM% instances, but this is not what I want...

Note: According to this post, there is a method in .NET (Path.GetTempFileName()) which does exactly what I am asking for (besides the wrong programming language obviously).

like image 537
aschipfl Avatar asked Aug 20 '15 01:08

aschipfl


2 Answers

Try next code snippet:

@echo off
setlocal EnableExtensions

rem get unique file name 
:uniqLoop
set "uniqueFileName=%tmp%\bat~%RANDOM%.tmp"
if exist "%uniqueFileName%" goto :uniqLoop

or create procedures

  • :uniqGet: create a file of a fix filename template (bat~%RANDOM%.tmp in your case);
  • :uniqGetByMask: create a file of a variable filename template. Note quadrupled percent signs of %random% reference in a procedure call: prefix%%%%random%%%%suffix.ext. Also note advanced usage: CALLing internal commands in call set "_uniqueFileName=%~2" inside the procedure.

The code could be as follows:

@ECHO OFF
SETLOCAL enableextensions
call :uniqGet uniqueFile1 "%temp%"
call :uniqGet uniqueFile2 "%tmp%"
call :uniqGet uniqueFile3 d:\test\afolderpath\withoutspaces
call :uniqGet uniqueFile4 "d:\test\a folder path\with spaces"

call :uniqGetByMask uniqueFile7 d:\test\afolder\withoutspaces\prfx%%%%random%%%%sffx.ext
call :uniqGetByMask uniqueFile8 "d:\test\a folder\with spaces\prfx%%%%random%%%%sffx.ext"

set uniqueFile

pause

goto :continuescript
rem get unique file name procedure
rem usage: call :uniqGetByMask VariableName "folderpath\prefix%%%%random%%%%suffix.ext"
rem parameter #1=variable name where the filename save to
rem parameter #2=folder\file mask
:uniqGetByMask
rem in the next line (optional): create the "%~dp2" folder if does not exist
md "%~dp2" 2>NUL
call set "_uniqueFileName=%~2"
if exist "%_uniqueFileName%" goto :uniqGetByMask
set "%~1=%_uniqueFileName%"
rem want to create an empty file? remove the `@rem` word from next line 
@rem type nul > "%_uniqueFileName%"
exit /B

goto :continuescript
@rem get unique file name procedure
@rem usage: call :uniqGet VariableName folder
@rem parameter #1=variable name where the filename save to
@rem parameter #2=folder where the file should be about
:uniqGet
@rem in the next line (optional): create the "%~2" folder if does not exist 
md "%~2" 2>NUL
set "_uniqueFileName=%~2\bat~%RANDOM%.tmp"
if exist "%_uniqueFileName%" goto :uniqGet
set "%~1=%_uniqueFileName%"
@rem want to create empty file? remove the `@rem` word from next line 
@rem type nul > "%_uniqueFileName%"
exit /B

:continueScript

Output:

==>D:\bat\SO\32107998.bat
uniqueFile1=D:\tempUser\me\bat~21536.tmp
uniqueFile2=D:\tempUser\me\bat~15316.tmp
uniqueFile3=d:\test\afolderpath\withoutspaces\bat~12769.tmp
uniqueFile4=d:\test\a folder path\with spaces\bat~14000.tmp
uniqueFile7=d:\test\afolder\withoutspaces\prfx26641sffx.ext
uniqueFile8=d:\test\a folder\with spaces\prfx30321sffx.ext
Press any key to continue . . .
like image 106
JosefZ Avatar answered Oct 02 '22 01:10

JosefZ


I suggest you one of two methods. The "technical approach" is to use JScript's FileSystemObject.GetTempName method. JScript is a programming language that comes pre-installed in all Windows versions from XP on, and its use in Batch via a "Batch-JScript" hybrid script is very simple:

@if (@CodeSection == @Batch) @then

@echo off
setlocal
for /F "delims=" %%a in ('CScript //nologo //E:JScript "%~F0"') do set "tempName=%%a"
echo Temp name: "%tempName%"
goto :EOF

@end

// JScript section

var fso = new ActiveXObject("Scripting.FileSystemObject");
WScript.Stdout.WriteLine(fso.GetTempName());

However, the simplest approach is to store a number in a data file and every time that you want a new name, get the number, increment it and store it back in the same file. This will work for "just" 2147483647 times!

rem Get next number
set /P "nextNum=" < NextNumber.txt
set /A nextNum+=1
echo %nextNum% > NextNumber.txt
set "tempName=File%nextNum%.txt"
echo Temp name: %tempName%
like image 4
Aacini Avatar answered Oct 02 '22 01:10

Aacini