views:

348

answers:

4

I'm trying to accomplish the following ridiculous task:

I have a text file containing a set of fully qualified filesnames. I want to iterate through the file and append each line to a common variable, that can be passed to a command line tool. For example, the file might be:

C:\dir\test.txt

C:\WINDOWS\test2.txt

C:\text3.txt

and I'd like to assign them to some variable 'a' such that:

a = "C:\dir\test.txt C:\WINDOWS\test2.txt C:\text2.txt"

A secondary question is - what is a good batch file reference? I'm finding some stuff in the Windows material, and a lot of home-grown websites, but nothing particularly complete.

Thanks!

A: 

What you're after can be done with a FOR /F command.

Here's a good resource I've used many times:

http://www.robvanderwoude.com/batchfiles.php

JRL
+5  A: 

As for references, SS64.com isn't bad. Rob van der Woude gets linked fairly often, too.


As for your problem, that's easy:

@echo off
setlocal enableextensions enabledelayedexpansion

set LIST=
for /f %%x in (yourfile.txt) do (
    set LIST=!LIST! "%%x"
)

echo %LIST%

endlocal


More in-depth explanation:

setlocal enableextensions enabledelayedexpansion

We're enabling delayed expansion here. This is crucial as otherwise we wouldn't be able to manipulate the list of files within the for loop that follows.

for /f %%x in (yourfile.txt) do (
    set LIST=!LIST! "%%x"
)

for /f iterates over lines in a file, so exactly what we need here. In each loop iteration we append the next line to the LIST variable. Note the use of !LIST! instead of the usual %LIST%. This signals delayed expansion and ensures that the variable gets re-evaluated every time this command is run.

Usually cmd expands variables to their values as soon as a line is read and parsed. For cmd a single line is either a line or everything that counts as a line, which happens to hold true for blocks delimited by parentheses like the one we used here. So for cmd the complete block is a single statement which gets read and parsed once, regardless of how often the interior of the loop runs.

If we would have used %LIST% here instead of !LIST! then the variable would have been replaced immediately by its value (empty at that point) and the loop would have looked like this:

for /f %%x in (yourfile.txt) do (
    set LIST= "%%x"
)

Clearly this isn't what we wanted. Delayed expansion makes sure that a variable is expanded only when its value is really needed. In this case when the interior of the loop runs and constructs a list of file names.

Afterwards the variable %LIST% or !LIST! (now it doesn't really matter anymore which to use) contains the list of lines from the file.

Funnily enough, the help for the set command includes exactly this example for delayed expansion:

Finally, support for delayed environment variable expansion has been added. This support is always disabled by default, but may be enabled/disabled via the /V command line switch to CMD.EXE. See CMD /?

Delayed environment variable expansion is useful for getting around the limitations of the current expansion which happens when a line of text is read, not when it is executed. The following example demonstrates the problem with immediate variable expansion:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "%VAR%" == "after" @echo If you see this, it worked
)

would never display the message, since the %VAR% in BOTH IF statements is substituted when the first IF statement is read, since it logically includes the body of the IF, which is a compound statement. So the IF inside the compound statement is really comparing "before" with "after" which will never be equal. Similarly, the following example will not work as expected:

set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%

in that it will NOT build up a list of files in the current directory, but instead will just set the LIST variable to the last file found. Again, this is because the %LIST% is expanded just once when the FOR statement is read, and at that time the LIST variable is empty. So the actual FOR loop we are executing is:

for %i in (*) do set LIST= %i

which just keeps setting LIST to the last file found.

Delayed environment variable expansion allows you to use a different character (the exclamation mark) to expand environment variables at execution time. If delayed variable expansion is enabled, the above examples could be written as follows to work as intended:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "!VAR!" == "after" @echo If you see this, it worked
)

set LIST=
for %i in (*) do set LIST=!LIST! %i
echo %LIST%
Joey
Johannes: thank you for the thorough answer - I'm slightly more enlightened about batch-files now. I've got a related question you might be interested in that I've posted as a new thread here:http://stackoverflow.com/questions/1506638/windows-batch-file-errorlevel-question
dls
A: 

A good book: Windows NT Shell Scripting by Tim Hill. The edition I have was published in 1998 but it is still valid for Windows command programs in Windows 2008.

A: 
type *commonfilepart* >> concat_result_file

OS: WINDOWS SERVER 2003

based2