Quantcast
Channel: EgonDev
Viewing all articles
Browse latest Browse all 10

Awk as a Templating Language

$
0
0

Preface

This is an article I wrote for work but I thought that it may be useful to others as well. It describes how to use awk as a simple templating language to run multiple command in a linux/unix environment. It talk specifically about a command we use called btq_submit which submits reports to our report queuing system but you could applied the technique to any comandline command.

This is a technique to use AWK to create an input and template to run reports. This method has a lot of over head so it will most likely only be useful where there is a report ran for many different sets of vars.

Overview

The command has 2 parts. The first part is the input. The input is what provides the information to the template. The template is the second part. It takes the input and writes out the btq_submit block.

#!/bin/sh
#test script for using awk to run reports
# vars
# store:[store num]:[store abbr]
# market:[market abbr]
#
# run line
# run:[department]:[start minor]:[end minor]
echo “
market:MSN\n
store:10:MAD\n
run:FURN:310:574Z\n
run:TV:000:046\n
run:STER:044:083Z\n
run:SE:084:149Z\n
run:COMP:150:249Z\n
run:APPL:250:309Z\n
store:12:EST\n
run:FURN:310:574Z\n
run:TV:000:046\n
run:STER:044:083Z\n
run:SE:084:149Z\n
run:COMP:150:249Z\n
run:APPL:250:309Z\n
“|awk ‘
BEGIN{
RS=”\n”;
FS=”:”;
}
/^market/{
market=$2;
}
/^store/{
store_num=$2;
store_abbr=$3;
}
/^#/ {
print “”;
print “echo \”"$0″\”";
print “”;
}
/^run/{
dept=$2
start_minor=$3;
end_minor=$4;
print “btq_submit -c H prclst <
print store_abbr” ” dept;
print market;
print store_num;
print start_minor;
print end_minor
print “AAAA”;
print “ZZZZ”;
print “A”;
print “2″;
print “N”;
print “N”;
print “N”;
print “N”;
print “”;
print “”;
print “END”;
print “”;
print “”;
}
‘|sh






<– Start of the input section








<– end of input

<– setting up vars in AWK











<– Start of run command that will make the btq_submit block

How AWK Works

What AWK does is that it takes input and then brakes that input in to records and fields. It then preforms actions on those records and field and produces output. If you look at our input section each line is one record. Each field in the record is separated by a :

example

run:FURN:310:574Z\n
  • Is one record
    • “\n” tells awk that this is the end of the record
  • Has 4 fields
    • field 1 is “run”
    • field 2 is “FURN”
    • field 3 is “310″
    • field 4 is “574Z”

Now if we want AWK to do something when it sees this record we need to make a block for it in the AWK command.

example

/^run/{

dept=$2;

start=$3;

end=$4;

print “dept is “dept”, start is “start”, end is “end;

}

The first part (/^run/) means: if the record start with run then do the following. The part inside the {} is the block of code to run. Here we are setting 3 vars from the feilds in the record. $[field number] is how you access the text in a field. $2 is the second field $3 is the third field … The last line is a print command. The sections in “” will be printed as text. Var names not in quotes will be substituted with there value.

The result returned by AWK for the above example is: dept is FURN, start is 310, end is 574Z

Parts of the Command

echo”[input]“|awk ‘[awk program]‘|sh

You must first echo your input and pipe it into the AWK command. You must then pipe the output of the AWK command to the shell if you want it to run the reports. You must have the “|sh” on the end if you want the script outputted by the AWK command to run. If you leave it off it will just output to the screen. This can be useful for debugging.

BEGIN block

At the start of the awk program there is a special block names BEGIN. The BEGIN block will execute before anything else in the awk program. In the begin block you have to set the separators that awk uses to tell the records and fields apart in the input. If you do not set these awk will default to RS=”\n” and FS=” “. Not normally what you want.

BEGIN{

RS=”\n”;

FS=”:”;

}

RS is the record separator

FS is the field separators

Setting Up the Vars

There are 2 ways to setup vars in this style of script. There is are persistent vars and there are run time vars.

Persistent

If you have one var that will be the same for several reports but not all reports you can use this method. If you look at the example the parts dealing with persistent vars are in green . In the input section they are written as [name]:[value1]:[value2] …  you can have as many values after the name as you want.

In the AWK section of the script you can see the sections that set the persistent var. the way these are written is

/^[name]/ {

[name of awk var1]=$2 #field 2 from input line;

[name of awk var1]=$3 #field 3 from input line;

}

The part in green is how AWK knows what to do with the line from the input. AWK reads each line and then looks for any blocks to apply to that line. What the /^name/ means to AWK is “if the record starts with [name] then do the following”.

example
If line starts with “market” then set the var market = to the second value in that line.

/^market/{market=$2;}

Once you set a var in AWK it will retain that value until it is reset or the AWK program exits. So vars you set outside the run block may be used for several reports.

At run time

If there vars that will change with each report you can include then in the run line. If you do not want to place them in their own vars you can use the $[field] notation.

The run Line

This is where AWK will output the btq_submit block. This is done using the print command. There will be 1 run line for each report you want the script to run.

example

/^run/{
dept=$2
start_minor=$3;
end_minor=$4;

print “btq_submit -c H prclst <
print store_abbr” ” dept;
print market;
print store_num;
print start_minor;
print end_minor
print “AAAA”;
print “ZZZZ”;
print “A”;
print “2″;
print “N”;
print “N”;
print “N”;
print “N”;
print “”;
print “”;
print “END”;
print “”;
print “”;
}

If this line is ran it will produce an a result like the following.

btq_submit -c H prclst <
COT APPL
STL
31
250
309Z
AAAA
ZZZZ
A
2
N
N
N
N

END

Making Switch Vars

Some times you may have a report parameter that is only different once or twice in a large number of reports. It would be a lot of extra work to state this parameter for every report just so it can be different once or twice. In these cases you can use this technique to make a switch var. A switch var is different from a normal var in that it has a default value. If you set a switch var the value you set it for will be used by the next report ran. The switch will then be set back to its default value and following reports will use the default value.

echo “
date:1-JUL-09\n
run:123:123\n
run:234:234\n

S_sort:S\n
run:234:234\n
“|awk ‘
BEGIN{
RS=”\n”;
FS=”:”;

S_sort=”D”;
}

/^date/{date=$2;}
/^S_sort/{S_sort=$2;}

/^run/{
s_minor=$2;
e_minor=$3;

print “btq_submit -c A reportName <
print date” “s_minor”-”e_minor;
print date;
print “ALL”;
print s_minor;
print e_minor;
print S_sort;
print “END”;

S_sort=”D”
}

In the example above the lines for the switch var are in red.

  • As far as the input part of the template you use the switch var the same way as you would use a normal var.
    • I like to name them starting with a capital S to show that it is a switch var and not a regular var.
  • In the BEGIN block you need to set the switch var to its default value.
  • Make a set block for the switch block in the same way as you would for a normal var.
  • it is used in the print btq_submit area the same as a normal var.
  • at the end of the run block set the switch var back to its default

You can have more then one switch var in a script, but you will need to have all of these parts for each one.

For loops

It is also possible to add looping to awk script. see the example below

#!/bin/sh
echo “test script \n\n\n”
echo “
date:3-jun-09\n
for_stores:MAD EST\n
run:xxy:123\n
run:yyy:234\n
for_stores:WAU OAK BDR;\n
run:yyx:345\n
run:yxx:456\n
“|awk ‘
BEGIN {
RS=”\n”;
FS=”:”;
}
/^date/{date=$2;}
/^for_stores/{split($2,stores,/ /);}
/^run/{
slp=$2;
minor=$3
print “#########  start loop  #########”;
for( i in stores){
print “btq_sumit report -c A <
print stores[i]” “date” and “slp;
print stores[i];
print date;
print slp;
print minor;
print “END”;
print “”;
}
}

#!/bin/sh

echo “test script \n\n\n”

echo “

date:3-jun-09\n

for_stores:MAD EST\n

run:xxy:123\n

run:yyy:234\n

for_stores:WAU OAK BDR;\n

run:yyx:345\n

run:yxx:456\n

“|awk ‘

BEGIN {

RS=”\n”;

FS=”:”;

}

/^date/{date=$2;}

/^for_stores/{split($2,stores,/ /);}

/^run/{

slp=$2;

minor=$3

print “######### start loop #########”;

for( i in stores){

print “btq_sumit report -c A <

print stores[i] ” “date” and “slp;

print stores[i] ;

print date;

print slp;

print minor;

print “END”;

print “”;

}

}

The output will look like this.

######### start loop #########

btq_sumit report -c A <

MAD 3-jun-09 and xxy

MAD

3-jun-09

xxy

123

END

btq_sumit report -c A <

EST 3-jun-09 and xxy

EST

3-jun-09

xxy

123

END

######### start loop #########

btq_sumit report -c A <

MAD 3-jun-09 and yyy

MAD

3-jun-09

yyy

234

END

btq_sumit report -c A <

EST 3-jun-09 and yyy

EST

3-jun-09

yyy

234

END

######### start loop #########

btq_sumit report -c A <

WAU 3-jun-09 and yyx

WAU

3-jun-09

yyx

345

END

btq_sumit report -c A <

OAK 3-jun-09 and yyx

OAK

3-jun-09

yyx

345

END

btq_sumit report -c A <

BDR; 3-jun-09 and yyx

BDR;

3-jun-09

yyx

345

END

######### start loop #########

btq_sumit report -c A <

WAU 3-jun-09 and yxx

WAU

3-jun-09

yxx

456

END

btq_sumit report -c A <

OAK 3-jun-09 and yxx

OAK

3-jun-09

yxx

456

END

btq_sumit report -c A <

BDR; 3-jun-09 and yxx

BDR;

3-jun-09

yxx

456

END

What is important to notice here is that each run line will submit a report for each of the vars that the for_ var is set for. It is also important to notice that the for_ var remands set after each run line. So multiple runs can be made with out reseting the for_ var.



Viewing all articles
Browse latest Browse all 10

Trending Articles