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 < |
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 S_sort=”D”; /^date/{date=$2;} /^run/{ print “btq_submit -c A reportName < 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.
