Progress 11: POSIX or bust
This is a proof of concept for zero knowledge traversal of a BAAML dataset declaring the datatypes of each property with it’s address.
The code below is the initial foundation for replacing perl
and RegEx.
#!/usr/bin/env sh
MyData=`cat <<\EOF
SpaceX
headquarters
address:Rocket Road
city:Hawthorne
state:California
links
website:https://www.spacex.com/
flickr:https://www.flickr.com/photos/spacex/
twitter:https://twitter.com/SpaceX
elon_twitter:https://twitter.com/elonmusk
name:SpaceX
founder:Elon Musk
founded:2002
employees:8000
EOF`
HuntMode="TabCount"; Level=0; PropName=""
while IFS= read -rn1 Char; do
if [ "$HuntMode" = "TabSearch" ]; then
# Look for tabs
if [ "$Char" = " " ]; then
HuntMode="TabCount"
fi
fi
if [ "$HuntMode" = "TabCount" ]; then
# Count tabs
if [ "$Char" = " " ]; then
(( Level = Level + 1 ))
else
# Property name found
# The property name array needs to be ready to have the next property name appended to it. It needs to be trimmed if the hierarchical $Level is the same or less than the number of property names present.
if [ "$(( $# - $Level))" -ge 0 ]; then
for i in $(seq 1 $#); do
[ "$i" -lt $Level ] && set -- "$@" "$1"
shift
done
fi
HuntMode="PropertyName"
fi
fi
if [ "$HuntMode" = "PropertyName" ]; then
# Gather property name
if [ "$Char" = ":" ] || [ "$Char" = "" ]; then
# Property name gathered, add to array
set -- "$@" "${PropName}"
# Reset state back to tab search skipping value
HuntMode="TabSearch"; Level=0; PropName=""
# Declare the property name and type for the demo
if [ "$Char" = ":" ]; then # Property is a value pair
echo "\"$@\" is a value pair"
elif [ "$Char" = "" ]; then # Property is a an object
echo "\"$@\" is an object"
fi
else
# Read property name
PropName="${PropName}${Char}"
fi
fi
done <<< $MyData
Output:
“SpaceX” is an object
“SpaceX headquarters” is an object
“SpaceX headquarters address” is a value pair
“SpaceX headquarters city” is a value pair
“SpaceX headquarters state” is a value pair
“SpaceX links” is an object
“SpaceX links website” is a value pair
“SpaceX links flickr” is a value pair
“SpaceX links twitter” is a value pair
“SpaceX links elon_twitter” is a value pair
“SpaceX name” is a value pair
“SpaceX founder” is a value pair
“SpaceX founded” is a value pair
“SpaceX employees” is a value pair
Takeaway:
POSIX Shell doesn’t have arrays but it can use arguments like an array.
I needed something to keep track of property names as the script moved through the hierarchy and this fit the bill. shift
makes it easy to remove arguments from the beginning but the tricky part was removing arguments from the end.
I came up with this:
set Setting 5 new array "elements here"
# Remove 2 arguments from the end
X=2
for i in $(seq 1 $#); do
[ "$i" -le $(($# - $X)) ] && set -- "$@" "$1"
shift
done
echo $@
Output:
Setting 5 new
- It loops as many times as there are arguments.
- Each loop takes the 1st argument and copies it to the end, then deletes the 1st argument.
- Unless… it’s within $X of the argument total in which case it doesn’t copy the 1st argument, it just deletes it.
- When the loop ends, all arguments are back in their original order and $X arguments are gone from the end.
Cheat sheet for more commands here: