'Nesting awk with variable in for loop?
I'm looking to turn this code into a for loop using awk with variable. It's a program that pulls the numbers under "totalframes", "landing lag", and "notes" for each of a character's aerial moves in Super Smash Bros. Example section of data:
<div class="movecontainer">
<div class="hitbox">
Normal<a class="hitboximg" data-featherlight="hitboxes/fox/FoxFAir.gif"></a>
Landing<a class="hitboximg" data-featherlight="hitboxes/fox/FoxFAirLanding.gif"></a>
</div>
<div class="movename">
Forward Air
</div>
<div class="startup">
7/11/16/21/26
</div>
<div class="totalframes">
43
</div>
<div class="landinglag">
18
</div>
<div class="notes">
Landing hit on frame 1. Autocancels on frame 46 onward
</div>
<div class="basedamage">
1.8/1.2/1.72.7/4.8/2.0
</div>
<div class="shieldlag">
4/4/4/5/12/9
</div>
<div class="shieldstun">
2/2/2/2/3/3
</div>
<div class="whichhitbox">
Last one is landing hitbox
</div>
<div class="advantage">
-14
</div>
<div class="activeframes">
7—8/11—12/16—17/21—22/26—27
</div>
</div>
<div class="movecontainer">
<div class="hitbox">
<a class="hitboximg" data-featherlight="hitboxes/fox/FoxBAir.gif"></a>
</div>
<div class="movename">
Back Air
</div>
<div class="startup">
9
</div>
<div class="totalframes">
48
</div>
<div class="landinglag">
9
</div>
<div class="notes">
Autocancels on frame 1-6 and 18 onward
</div>
<div class="basedamage">
13.0
</div>
<div class="shieldlag">
9
</div>
<div class="shieldstun">
5
</div>
<div class="whichhitbox">
--
</div>
<div class="advantage">
-4
</div>
<div class="activeframes">
9—11
</div>
</div>
<div class="movecontainer">
<div class="hitbox">
<a class="hitboximg" data-featherlight="hitboxes/fox/FoxUAir.gif"></a>
</div>
<div class="movename">
Up Air
</div>
<div class="startup">
9/12
</div>
<div class="totalframes">
35
</div>
<div class="landinglag">
13
</div>
<div class="notes">
Autocancels on frame 1-8 and 25 onward
</div>
<div class="basedamage">
5.0/10.0
</div>
<div class="shieldlag">
6/8
</div>
<div class="shieldstun">
3/4
</div>
<div class="whichhitbox">
First/Second
</div>
<div class="advantage">
-10/-9
</div>
<div class="activeframes">
9—10/12—13
</div>
</div>
Desired output:
Forward
43
18
46
Back
48
9
18
Up
35
13
25
Down
49
17
28
Neutral
38
7
32
Current solution:
echo -n "Character: "
read char
awk '/Forward Air$/{print $1; getline; getline; getline; getline; getline; getline; print $1; getline; getline; getline; print $1; getline; getline; getline; print $0}' data/chars/$char > output.txt
awk '/Back Air$/{print $1; getline; getline; getline; getline; getline; getline; print $1; getline; getline; getline; print $1; getline; getline; getline; print $0}' data/chars/$char >> output.txt
awk '/Up Air$/{print $1; getline; getline; getline; getline; getline; getline; print $1; getline; getline; getline; print $1; getline; getline; getline; print $0}' data/chars/$char >> output.txt
awk '/Down Air$/{print $1; getline; getline; getline; getline; getline; getline; print $1; getline; getline; getline; print $1; getline; getline; getline; print $0}' data/chars/$char >> output.txt
awk '/Neutral Air$/ {print $1; getline; getline; getline; getline; getline; getline; print $1; getline; getline; getline; print $1; getline; getline; getline; print $0}' data/chars/$char >> output.txt
grep -o -E ".{0,3}onward.{0,1}" output.txt > output2.txt
awk '{print $1}' output2.txt > output3.txt
The easiest way to simplify would seem to be to create a for loop, (e.g. "For ("Forward Air", "Back Air", "Up Air", "Down Air", "Neutral Air"), execute awk function"), but I haven't had any luck finding the correct syntax for this.
The getline spam is clunky, but I'm ignoring that for now because I learned that there are better tools than awk. I mainly just want to turn this into a for loop with awk using variable.
Solution 1:[1]
This might be what you want with awk:
$ awk '
f { print $(/Autocancels/ ? NF-1 : 1); f=0 }
/<div class="(movename|totalframes|landinglag|notes)">/ { f=1 }
' file
Forward
43
18
46
Back
48
9
18
Up
35
13
25
Solution 2:[2]
You could use xsltproc instead of awk.
This piece of code gives you a first draft of what you try to achieve:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:template match="/">
<xsl:for-each select="//div[@class = 'movecontainer']">
<xsl:value-of select="normalize-space(
div[@class = 'movename']/child::text())"/>
<xsl:text>
</xsl:text><!-- insert new line -->
<xsl:value-of select="normalize-space(
div[@class = 'totalframes']/child::text())"/>
<xsl:text>
</xsl:text><!-- insert new line -->
<xsl:value-of select="normalize-space(
div[@class = 'landinglag']/child::text())"/>
<xsl:text>
</xsl:text><!-- insert new line -->
<xsl:value-of select="normalize-space(
div[@class = 'notes']/child::text())"/>
<xsl:text>
</xsl:text><!-- insert new line -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Assuming the stylesheet above is called prog.xsl and your input stays in a well formed XML file called input.xml, you can launch xsltproc as follows:
xsltproc prog.xsl input.xml
It will produce next output that still needs to be fine tuned:
Forward Air
43
18
Landing hit on frame 1. Autocancels on frame 46 onward
Back Air
48
9
Autocancels on frame 1-6 and 18 onward
Up Air
35
13
Autocancels on frame 1-8 and 25 onward
If this works for you, you have to add code for removing the string "Air" at the end of the movename field, and for extracting the number you want from the note field.
You could also filter this output through awk or sed for cleaning it according to your needs, as in:
xsltproc prog.xsl input.xml | sed -e '/ Air/s///' -e 's/^.* \([0-9]*\) onward$/\1/'
which gives you the output you want.
If you prefer awk to sed, use next filter on the output of xsltproc:
xsltproc prog.xsl input.xml | awk '/Air/{print $1; next}/Autocancels/{print $(NF-1); next}1'
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ed Morton |
| Solution 2 |
