Clinician's
corner

Back to main page

Programmer's
corner
So, you use WinBUGS a lot? Want more?
Patrick Blisle
Division of Clinical Epidemiology
McGill University Health Center
Montreal, Quebec CANADA
patrick.belisle@rimuhc.ca

Last modification: 4 jul 2012















Version 1.4.1 (July 2015)
loop
Repeating code with slight modifications at each iteration
[ Loop is a Perl program that automates the writing of code wherein small changes are made to otherwise identical sections. ]


The present document introduces the reader to the syntax of loop input files and gives a few examples that will hopefully make its use straightforward.
Top
Syntax

The input files that loop will read are plain text files consisting of the text/code to repeat preceded by a header and the list of variables to loop over, along with the values taken for each of them. The header first gives the output file location (surrounded by double quotes if it includes a space in its name) optionally followed by a series of parameters. Then follows the block of variables to loop over, embedded between opening and closing curly brackets, listing the variables (or pieces of code) to be replaced in the remaining code along with the values to replace each of them, one variable per line.


output_file.txt [options]
{
    variable1     value1a value1b value1c
    variable2     value2a value2b
    variable3     value3a value3b value3c value3d
    ...
    variableJ     valueJa valueJb
}

Some code with <variable1>
<variable2>, <variable3>,
... <variableJ> appearing and to be replaced by their corresponding values
for each possible combination.


Top
Details

The exhaustive list of loop options (to be used on top line of input files) is given below.


Option Signification Comment
-b opening_and_closing_brackets opening and closing brackets surrounding bits of code to be replaced; Default are < and >.
See example.
-c comment_leading_character leading character for comment split line; Default is #.
-w width total width of comment split line; Default is 120.
-nosep use when no comment split line is to be printed in output script; See example.
-m to write repeated/modified code to multilple output script files rather to a single output script; If output script file given on first line is ../myscript.txt, -m option will send the modified script to output files ../myscript-1.txt, ../myscript-2.txt, ../myscript-3.txt, etc.

If there is only one variable to loop over, then output script file names will rather be suffixed by that variable values rather than 1, 2, 3, etc.; for example, if X takes values {alpha, beta, gamma}, then output script file names will be ../myscript-alpha.txt, ../myscript-beta.txt and ../myscript-gamma.txt.
-m# same as -m, but where suffix in output file names is forced to be consecutive integers even though there is only one variable to loop over;
-null null_string defines a keyword representing a blank; When a loop variable takes that value, it will not appear in the resulting text/code.
See example.
-sl skipLine_string defines a keyword indicating to skip a line; When a loop variable takes that value, the line on which it appears will not be printed to the output.
See example.
-klb|-plb
-ktb|-ptb
indicate to keep/preserve leading and trailing blanks, respectively; By default, leading/trailing blanks are not preserved.
See example.



Top
Examples


Example 1

First, a very simple example. The code below, when submitted to loop,

MyText.txt -w 60
{
    S     rat mouse
    L     cow camel
}

Biology lesson
A <S> is a small animal.
A <L> is a large animal.

would write the text below to file MyText.txt.
Biology lesson
A rat is a small animal.
A cow is a large animal.
# ----------------------------------------------------------
Biology lesson
A rat is a small animal.
A camel is a large animal.
# ----------------------------------------------------------
Biology lesson
A mouse is a small animal.
A cow is a large animal.
# ----------------------------------------------------------
Biology lesson
A mouse is a small animal.
A camel is a large animal.

Example 2 / Without seperation lines

Under some circumstances, separation lines may not be suitable. The use of -nosep option would prevent the writing of comment/separation lines, as illustrated by the following input file

MyText.txt -nosep
{
    S     rat mouse
    L     cow camel
}

Biology lesson
A <S> is a small animal.
A <L> is a large animal.

which would write the code below to file MyText.txt.
Biology lesson
A rat is a small animal.
A cow is a large animal.
Biology lesson
A rat is a small animal.
A camel is a large animal.
Biology lesson
A mouse is a small animal.
A cow is a large animal.
Biology lesson
A mouse is a small animal.
A camel is a large animal.

Example 3

In the above example, the absence of separation lines makes the output file less readable. An alternative would be to have blank lines as separation lines, which is what is obtained through the use of -blanksep option, or, equivalently, through a zero-length separation line, specified through option -w 0.

MyText.txt -blanksep
{
    S     rat mouse
    L     cow camel
}

Biology lesson
A <S> is a small animal.
A <L> is a large animal.

Biology lesson
A rat is a small animal.
A cow is a large animal.

Biology lesson
A rat is a small animal.
A camel is a large animal.

Biology lesson
A mouse is a small animal.
A cow is a large animal.

Biology lesson
A mouse is a small animal.
A camel is a large animal.

Example 4

Note that leading and trailing blanks in the script used in Example 1, highlighted in light purple and light pink below, were not preserved in output code; they are indeed not preserved by default.

MyText.txt -w 60
{
    S     rat mouse
    L     cow camel
}
 
Biology lesson
A <S> is a small animal.
A <L> is a large animal.
 
 

The use of -klb or -ktb options would preserve leading blanks and trailing blanks respectively. Script below would preserver leading blanks, as following output shows.

MyText.txt -w 60 -klb
{
    S     rat mouse
    L     cow camel
}
 
Biology lesson
A <S> is a small animal.
A <L> is a large animal.
 
 


Biology lesson
A rat is a small animal.
A cow is a large animal.
# ----------------------------------------------------------

Biology lesson
A rat is a small animal.
A camel is a large animal.
# ----------------------------------------------------------

Biology lesson
A mouse is a small animal.
A cow is a large animal.
# ----------------------------------------------------------

Biology lesson
A mouse is a small animal.
A camel is a large animal.


Next few examples will write some code to prepare scripts along the lines of input files to WriteWinBUGSScript.

Example 5

An input file consisting in the following code

../prev.txt -w 60
{
    COUNTRY     Canada Sweden
    SENS     Pessimistic MostLikely Optimistic
}

models/model.txt 5k/20k
-d data/<COUNTRY>.txt
-d data/parms/sens-<SENS>.txt
-i inits/parms.txt
-s scripts/<COUNTRY>-<SENS>.txt
-o log/<COUNTRY>-<SENS>

would repeat the code below the curly bracket 6 times — once for each combination of COUNTRY × SENS — and the resulting code would be saved to file ../prev.txt, reproduced below.

Note that -w option was used to make the comment line shorther than the default length (120).
# ----------------------------------------------------------
models/model.txt 5k/20k
-d data/Canada.txt
-d data/parms/sens-Pessimistic.txt
-i inits/parms.txt
-s scripts/Canada-Pessimistic.txt
-o log/Canada-Pessimistic
# ----------------------------------------------------------
models/model.txt 5k/20k
-d data/Canada.txt
-d data/parms/sens-MostLikely.txt
-i inits/parms.txt
-s scripts/Canada-MostLikely.txt
-o log/Canada-MostLikely
# ----------------------------------------------------------
models/model.txt 5k/20k
-d data/Canada.txt
-d data/parms/sens-Optimistic.txt
-i inits/parms.txt
-s scripts/Canada-Optimistic.txt
-o log/Canada-Optimistic
# ----------------------------------------------------------
models/model.txt 5k/20k
-d data/Sweden.txt
-d data/parms/sens-Pessimistic.txt
-i inits/parms.txt
-s scripts/Sweden-Pessimistic.txt
-o log/Sweden-Pessimistic
# ----------------------------------------------------------
models/model.txt 5k/20k
-d data/Sweden.txt
-d data/parms/sens-MostLikely.txt
-i inits/parms.txt
-s scripts/Sweden-MostLikely.txt
-o log/Sweden-MostLikely
# ----------------------------------------------------------
models/model.txt 5k/20k
-d data/Sweden.txt
-d data/parms/sens-Optimistic.txt
-i inits/parms.txt
-s scripts/Sweden-Optimistic.txt
-o log/Sweden-Optimistic

Example 6 / Using alternative opening and closing brackets

Following code, where brackets surrounding pieces of code to be replaced are changed to curly brackets, leads to the same output file as in previous example.

../prev.txt -w 60 -b { }
{
    COUNTRY     Canada Sweden
    M     1 2
}

models/model-{M}.txt 5k/20k
-d data/{COUNTRY}.txt
-d data/parms/sens-MostLikely.txt
-i inits/parms.txt
-s scripts/{COUNTRY}-MostLikely.txt
-o log/{COUNTRY}-MostLikely


Example 7 / Linking variables

Each new line in the block of variables to loop over multiplies the number of resulting blocks of code, as it multiplies the number of variable values combinations.

That is not true when a variable is linked to another, like variable T in example below. In this example, variable T does not multiply by three the number of possible combinations, since it is linked to variable COUNTRY: <T> will be replaced by cold when COUNTRY=Canada, by warm when COUNTRY=Mexico and by cold when COUNTRY=Sweden (values read for a linked variable — like T in example below — are associated to values of the variable it is linked to — COUNTRY, in this example — in the same order as they are listed).

../prev.txt -w 60 -blanksep
{
    COUNTRY     Canada Mexico Sweden
    M     1 2
    T{COUNTRY}     cold warm cold
}

models/model-<M>.txt 5k/20k
-d data/<COUNTRY>.txt
-d data/parms/prior-<T>.txt
-d data/parms/sens-MostLikely.txt
-i inits/parms.txt
-s scripts/<COUNTRY>-MostLikely-<M>.txt
-o log/<COUNTRY>-MostLikely-<M>

The output to code above would be as reproduced below.
models/model-1.txt 5k/20k
-d data/Canada.txt
-d data/parms/prior-cold.txt
-d data/parms/sens-MostLikely.txt
-i inits/parms.txt
-s scripts/Canada-MostLikely-1.txt
-o log/Canada-MostLikely-1

models/model-2.txt 5k/20k
-d data/Canada.txt
-d data/parms/prior-cold.txt
-d data/parms/sens-MostLikely.txt
-i inits/parms.txt
-s scripts/Canada-MostLikely-2.txt
-o log/Canada-MostLikely-2

models/model-1.txt 5k/20k
-d data/Mexico.txt
-d data/parms/prior-warm.txt
-d data/parms/sens-MostLikely.txt
-i inits/parms.txt
-s scripts/Mexico-MostLikely-1.txt
-o log/Mexico-MostLikely-1

models/model-2.txt 5k/20k
-d data/Mexico.txt
-d data/parms/prior-warm.txt
-d data/parms/sens-MostLikely.txt
-i inits/parms.txt
-s scripts/Mexico-MostLikely-2.txt
-o log/Mexico-MostLikely-2

models/model-1.txt 5k/20k
-d data/Sweden.txt
-d data/parms/prior-cold.txt
-d data/parms/sens-MostLikely.txt
-i inits/parms.txt
-s scripts/Sweden-MostLikely-1.txt
-o log/Sweden-MostLikely-1

models/model-2.txt 5k/20k
-d data/Sweden.txt
-d data/parms/prior-cold.txt
-d data/parms/sens-MostLikely.txt
-i inits/parms.txt
-s scripts/Sweden-MostLikely-2.txt
-o log/Sweden-MostLikely-2

Example 8 / Replacing a parameter with nothing

The previous example wrote script for models saved into two files, models/model-1.txt and models/model-2.txt. If you wanted to include a model saved in models/model.txt in the same code as above, you would need to indicate to Loop to drop <M> in one of the loops, that is, to replace it by nothing. This can be done via the definition of a null string through the -null option, as shown in code below.

../prev.txt -w 60 -blanksep -null NULL
{
    COUNTRY     Canada Sweden
    M     NULL -1 -2
}

models/model<M>.txt 5k/20k
-d data/<COUNTRY>.txt
-i inits/parms.txt
-s scripts/<COUNTRY><M>.txt
-o log/<COUNTRY><M>

The output to code above is as follows.
models/model.txt 5k/20k
-d data/Canada.txt
-i inits/parms.txt
-s scripts/Canada.txt
-o log/Canada

models/model-1.txt 5k/20k
-d data/Canada.txt
-i inits/parms.txt
-s scripts/Canada-1.txt
-o log/Canada-1

models/model-2.txt 5k/20k
-d data/Canada.txt
-i inits/parms.txt
-s scripts/Canada-2.txt
-o log/Canada-2

models/model.txt 5k/20k
-d data/Sweden.txt
-i inits/parms.txt
-s scripts/Sweden.txt
-o log/Sweden

models/model-1.txt 5k/20k
-d data/Sweden.txt
-i inits/parms.txt
-s scripts/Sweden-1.txt
-o log/Sweden-1

models/model-2.txt 5k/20k
-d data/Sweden.txt
-i inits/parms.txt
-s scripts/Sweden-2.txt
-o log/Sweden-2

Example 9 / Values with spaces

In each example above, spaces are used as field delimiters. If a parameter is to take values with spaces, e.g. if example above involved Puerto Rico, one would need the space between its two parts not to be consided as a field delimiter. A work-around is to use an alternate field delimiter for the corresponding variable.

A field delimiter different from a blank is defined by following the line-leading parameter name by the field delimiter (which will apply for that parameter only). Code below uses comma (,) as a field delimiter on the COUNTRY values declaration line.

../prev.txt -w 60 -blanksep
{
    COUNTRY,    Canada,Puerto Rico,Sweden
    M     1 2
}

models/model-<M>.txt 5k/20k
-d data/<COUNTRY>.txt
-i inits/parms.txt
-s scripts/<COUNTRY>-<M>.txt
-o log/<COUNTRY>-<M>

It would lead to the output below.
models/model-1.txt 5k/20k
-d data/Canada.txt
-i inits/parms.txt
-s scripts/Canada-1.txt
-o log/Canada-1

models/model-2.txt 5k/20k
-d data/Canada.txt
-i inits/parms.txt
-s scripts/Canada-2.txt
-o log/Canada-2

models/model-1.txt 5k/20k
-d data/Puerto Rico.txt
-i inits/parms.txt
-s scripts/Puerto Rico-1.txt
-o log/Puerto Rico-1

models/model-2.txt 5k/20k
-d data/Puerto Rico.txt
-i inits/parms.txt
-s scripts/Puerto Rico-2.txt
-o log/Puerto Rico-2

models/model-1.txt 5k/20k
-d data/Sweden.txt
-i inits/parms.txt
-s scripts/Sweden-1.txt
-o log/Sweden-1

models/model-2.txt 5k/20k
-d data/Sweden.txt
-i inits/parms.txt
-s scripts/Sweden-2.txt
-o log/Sweden-2

Example 10 / Output files modified by variable values

Loop output files, specified on the first line of the script, can include parts that will vary with the variables included in the script. Code below, for example, would save output to two separate files, namely ../prev-Canada.txt and ../prev-Sweden.txt.

../prev-<COUNTRY>.txt -w 60 -blanksep
{
    COUNTRY     Canada Sweden
    M     1 2
}

models/model-<M>.txt 5k/20k
-d data/<COUNTRY>.txt
-i inits/parms.txt
-s scripts/<COUNTRY>-<M>.txt
-o log/<COUNTRY>-<M>

The two output files will be ../prev-Canada.txt
models/model-1.txt 5k/20k
-d data/Canada.txt
-i inits/parms.txt
-s scripts/Canada-1.txt
-o log/Canada-1

models/model-2.txt 5k/20k
-d data/Canada.txt
-i inits/parms.txt
-s scripts/Canada-2.txt
-o log/Canada-2
and ../prev-Sweden.txt, below.
models/model-1.txt 5k/20k
-d data/Sweden.txt
-i inits/parms.txt
-s scripts/Sweden-1.txt
-o log/Sweden-1

models/model-2.txt 5k/20k
-d data/Sweden.txt
-i inits/parms.txt
-s scripts/Sweden-2.txt
-o log/Sweden-2

Example 11 / Skipping lines / omitting text

Sometimes, some lines of code/text are not be reproduced in output file for some iterations in the loop. The code below, when submitted to loop,

MyText.txt -w 60 -null NULL -sl SKIP
{
    S     small large
    X{S}     SKIP NULL
}

I like <S> animals.
I like elephants in particular.<X>
I visit zoos each summer.

would write the text below to file MyText.txt.
I like small animals.
I visit zoos each summer.
# ----------------------------------------------------------
I like large animals.
I like elephants in particular.
I visit zoos each summer.

Example 12 / Adding comments to your script

It is often useful to include comments to a loop source file (or script), e.g. to give indications on the context in which that script was written.
Comments are to be placed on top lines of the script and begin with a sharp symbol (#).

These comments will not appear in the loop output files. Code below, with one line of comment on top, would produce the same output as previous example.

# Prepared for my son presentation at kindergarten.

MyText.txt -w 60 -null NULL -sl SKIP
{
    S     small large
    X{S}     SKIP NULL
}

I like <S> animals.
I like elephants in particular.<X>
I visit zoos each summer.

would write the text below to file MyText.txt.


Top
Download loop

loop is a free program: version 1.4.1 is directly available from this page. Save and unzip it and read the section below.

Top
How to use loop

loop is a program written in Perl. Please refer to my generic page on running Perl programs for instructions.


Log file

Success or error messages are written to the log file loop.log, found in the directory where you saved loop.pl.