Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Looking for ideas on how to implement an equivalent to C's tmpfile function in batch.

4 views
Skip to first unread message

Cyberclops

unread,
Aug 17, 2009, 4:57:58 PM8/17/09
to
I find that as my batch files get more and more sophisticated, I am
making more use of temporary files. As of right now I am hard coding
these temporary file names but I realize that if I run the risk of
collisions. Back in my C programming days there were a couple of
functions that helped get around this ...

tmpfile would create a temporary file with a unique name
tmpnam would return the unique name

I think that these can be combined into one for batch file purposes

I would like to implement a function that creates a zero byte file
with a unique name and then returns that name in an environment
variable. This function should be able to be called multiple times
with no collisions.

Here is how it would be used

call :tmpfile NAME
< use file %NAME% as needed without worry about collisions>
del %NAME%

My idea so far is to use create a file in the format _<number>.tmp in
the %TEMP% directory.

:tmpfile
setlocal enableextensions enabledelayedexpansion
set /a NUM=0
:more
if not exist "%TEMP%\_%NUM%.tmp" goto done
set /a NUM+=1
goto more
:done
rem > "%TEMP%\_%NUM%.tmp"
endlocal& set %1=%TEMP%\_%NUM%.tmp


Will this work? Does anybody have any better ideas?

Thanks!

Pegasus

unread,
Aug 17, 2009, 5:03:24 PM8/17/09
to

"Cyberclops" <lowell...@gmail.com> wrote in message
news:a77a6a10-e3b1-4e3f...@c29g2000yqd.googlegroups.com...

Instead of starting your file name with 0, you could seed it with the
%random% variable, thus getting a unique file name in most cases. You also
do not need the EnableDelayedExpansion statement for this code fragment.


foxidrive

unread,
Aug 17, 2009, 5:46:21 PM8/17/09
to
On Mon, 17 Aug 2009 13:57:58 -0700 (PDT), Cyberclops
<lowell...@gmail.com> wrote:

>I find that as my batch files get more and more sophisticated, I am
>making more use of temporary files. As of right now I am hard coding
>these temporary file names but I realize that if I run the risk of
>collisions. Back in my C programming days there were a couple of
>functions that helped get around this ...
>
>tmpfile would create a temporary file with a unique name
>tmpnam would return the unique name
>
>I think that these can be combined into one for batch file purposes
>
>I would like to implement a function that creates a zero byte file
>with a unique name and then returns that name in an environment
>variable. This function should be able to be called multiple times
>with no collisions.
>
>Here is how it would be used
>
>call :tmpfile NAME
>< use file %NAME% as needed without worry about collisions>
>del %NAME%

As Pegasus says, the random variable will suffice:

:name
set name=%random%
if not exist "format_%name%.tmp" (set name=format_%name%.tmp
) else (goto :name)


Ted Davis

unread,
Aug 17, 2009, 8:17:56 PM8/17/09
to
On Mon, 17 Aug 2009 13:57:58 -0700, Cyberclops wrote:

> I find that as my batch files get more and more sophisticated, I am making
> more use of temporary files. As of right now I am hard coding these
> temporary file names but I realize that if I run the risk of collisions.
> Back in my C programming days there were a couple of functions that helped
> get around this ...
>
> tmpfile would create a temporary file with a unique name tmpnam would
> return the unique name
>

I used to form a name from the date and time with quite a bit of
processing. Now I use the GnuWin32 DATE utility (renamed gnudate.exe) to
generate the name, usually as the number of seconds since the C epoch:

for /f %%A in ('gnudate +%%s') do set tempfile=%%A

I can define the directory and extension if I want by putting them around
the second %%A. These names have the sometimes useful characteristic that
they sort properly in chronological order of creation.

DATE is one of the CoreUtils:
<http://gnuwin32.sourceforge.net/packages/coreutils.htm>.


--

T.E.D. (tda...@mst.edu)

billious

unread,
Aug 18, 2009, 2:34:40 AM8/18/09
to

"Cyberclops" <lowell...@gmail.com> wrote in message
news:a77a6a10-e3b1-4e3f...@c29g2000yqd.googlegroups.com...

This solution developed using XP
It may work for NT4/2K

----- batch begins -------
[1]@echo off
[2]:loop
[3]set tempfilename=%temp%\%random%.txt
[4]if not exist "%tempfilename%" (copy nul "%tempfilename%" >nul) else goto
loop
[5]echo %tempfilename%
[6]:: another method
[7]set tempfilename=%random%
[8]:loop2
[9]set tempfilename=x%tempfilename%
[10]if exist "%tempfilename%.*" goto loop2
[11]copy nul "%tempfilename%.txt" >nul
[12]echo %tempfilename%
------ batch ends --------

Lines start [number] - any lines not starting [number] have been wrapped and
should be rejoined. The [number] that starts the line should be removed

with the first method, a full filname will be generated. An obvious
enhancement would be to replace the hard-wired %temp% with %~1\ to allow the
directory to be specified as a parameter - perhaps defaulting to %temp% or
"." if %1 is not provided.

With the second method, tempfilename is a unique name-only, so instead of
needing to call the routine for each tempfile required, any extent can be
added safely. [11] acts simply to force a %tempfilename%.txt to exist, and
deleting %tempfilename%.* cleans up nicely.

Mixing and matching directories and defaults gives you endless
possibilities...


Dr J R Stockton

unread,
Aug 18, 2009, 8:02:49 AM8/18/09
to
In alt.msdos.batch.nt message <a77a6a10-e3b1-4e3f-8e96-cdcdcbee2501@c29g
2000yqd.googlegroups.com>, Mon, 17 Aug 2009 13:57:58, Cyberclops
<lowell...@gmail.com> posted:

>I would like to implement a function that creates a zero byte file
>with a unique name and then returns that name in an environment
>variable. This function should be able to be called multiple times
>with no collisions.

(1) SET DT=$$$%date%$$$%time%$$$
(2) Using substrings, remove the date and time separators from DT
(3) If a file of that name exists, GO TO 1.

If your system is ISO 8601 compliant, you'll get something like
$$$20090818$123456.79$; if not, repent or adjust the above accordingly.

If a few different parts of a script require a few unique names in rapid
succession, you can add a letter suffix to reduce delays.

The purpose of the $ characters is to make all of those appear together
in a listing, and to render unlikely a clash with other software using a
similar system. Replace some of them with other legal but uncommon
characters.

You can add to the above %random% which is unlikely to repeat soon.

--
(c) John Stockton, nr London, UK. ?@merlyn.demon.co.uk Turnpike v6.05.
Web <URL:http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
PAS EXE etc : <URL:http://www.merlyn.demon.co.uk/programs/> - see 00index.htm
Dates - miscdate.htm estrdate.htm js-dates.htm pas-time.htm critdate.htm etc.

Esra Sdrawkcab

unread,
Aug 18, 2009, 5:28:01 PM8/18/09
to
On Tue, 18 Aug 2009 13:02:49 +0100, Dr J R Stockton
<repl...@merlyn.demon.co.uk> wrote:

> In alt.msdos.batch.nt message <a77a6a10-e3b1-4e3f-8e96-cdcdcbee2501@c29g
> 2000yqd.googlegroups.com>, Mon, 17 Aug 2009 13:57:58, Cyberclops
> <lowell...@gmail.com> posted:
>
>> I would like to implement a function that creates a zero byte file
>> with a unique name and then returns that name in an environment
>> variable. This function should be able to be called multiple times
>> with no collisions.

I may have missed it, but this exists already; just create a piped file:

rem|dir %temp%\*. /b

Oh bother only works on "real" DOS, well certainly not XP.


Timo Salmi

unread,
Aug 18, 2009, 7:34:50 PM8/18/09
to
Cyberclops wrote:
> I would like to implement a function that creates a zero byte file
> with a unique name and then returns that name in an environment
> variable. This function should be able to be called multiple times
> with no collisions.

41} How can I create a zero-byte file? How do I test for it?
http://www.netikka.net/tsneti/info/tscmd041.htm

87} How can I create a four-digit random string?
http://www.netikka.net/tsneti/info/tscmd087.htm
and/or
1} How to get today's date (and time) elements into environment variables?
http://www.netikka.net/tsneti/info/tscmd001.htm

All the best, Timo

--
Prof. Timo Salmi mailto:t...@uwasa.fi ftp & http://garbo.uwasa.fi/
Hpage: http://www.uwasa.fi/laskentatoimi/english/personnel/salmitimo/
Department of Accounting and Finance, University of Vaasa, Finland
Useful CMD script tricks http://www.netikka.net/tsneti/info/tscmd.htm

Frank P. Westlake

unread,
Aug 20, 2009, 6:27:12 AM8/20/09
to
"Cyberclops" news:a77a6a10-e3b1-4e3f...@c29g2000yqd.googlegroups.com...

>I find that as my batch files get more and more sophisticated, I am
> making more use of temporary files. As of right now I am hard coding
> these temporary file names but I realize that if I run the risk of
> collisions.

After having thunk about this for a while I thank that in many situations it would be better to create a unique subdirectory in %TEMP% and then to use hard coded filenames within the subdirectory. When the script completes it need only 'RD /S /Q' to delete all its temporary files. This should also be a faster delete if there are many files. The subdirectory name can also be used to identify a misbehaving script if you include something meaningful, such as '%~n0'. The hardcoded filenames within the subdirectory could also be meaningful.

The use of %RANDOM% isn't always helpful in this case. If a script is piped to another instance of itself (base64.cmd /encode | base64.cmd /decode) Then "%~n0" and "%RANDOM% will be the same for both instances. So I use "%TIME%" and take out the colon, the space, and the dot.

Frank

Drink, drank, drunk.
Think, thank, thunk?

Ted Davis

unread,
Aug 20, 2009, 9:30:17 AM8/20/09
to

Well, "thunk down" is what earlier Win32 versions did to switch to 16 bit
mode.

Something like this?

set basedir=.
if exist %temp% set basedir=%temp%
for /f %%A in ('gnudate +%%d%%m%%Y%%H%%M%%S') do set basedir=%basedir%\%~n0_%%A\
md %basedir%
:: create some files in %basedir%
:: do other things
rd /s /q %basedir%
set basedir=

where gnudate is renamed from the GnuWin32 date.exe to which I provided a
link elsewhere in this thread.

Of course, dot as the default base directory is not pointless, and the
example shows setting it to a defined default if %temp% is not defined or
doesn't exist, both of which I have encountered. Without *something* in
place of %temp% if it isn't defined, the directory would be created in the
root of the default drive, not usually something considered desirable, and
sometimes (R/O media) not even possible. If the script is on media where
it is bot desirable to have the temp directory, some code should be used
to find a suitable location.

Note that I incorporated your suggestion to include the script name, but
put it in the script's own temp directory name. %userprofile%, if it
exists is often suitable.

--
T.E.D. (tda...@mst.edu)

0 new messages