Progress 15: The first step toward the elegant answer
Re-beating the 1st challenge in pure BASH
MY_DATA=`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`
Posted here (and below) was an answer to a self-challenge that I set that I could a read multi-dimensional associate arrays in BASH in < 10 lines.
Sadly that was “BASH” in big air quotes because it was really a RegEx string generator for grep
to find the result using PCRE (why I later renamed it BAAMX) and if the BAAML had newlines they had to be removed.
# If the database has newlines, old BAAM needs them removed:
MY_DATA=${MY_DATA//$'\n'/}
BAAM (){ # BAAM - [B]ASH [A]ssociative [A]rrarys in [M]ulti-dimensions
REGEX_STR='(^|[^\t])\t{1}'$2'((?=\t{2}[^\t])|:)\K.*?'
LEVEL=1
for PROP_NAME in "${@:3}"; do
REGEX_STR+='\t{'$((LEVEL++))'}'$PROP_NAME'((?=\t{'$(($LEVEL+1))'}[^\t])|:)\K.*?'
done
REGEX_STR+='[^\t](?=$|\t{1,'$LEVEL'}[^\t])'
echo $(echo "$1" | grep -oPe "$REGEX_STR")
}
Here’s the solution in 9 lines of pure BASH 10 months later.
BAAM (){ # BAAM - [B]ASH [A]ssociative [A]rrarys in [M]ulti-dimensions
DbLayer=$1; shift; Blocks=
for Prop in "$@"; do
Blocks=$Blocks' '
DbLayerNext=${DbLayer#*$Blocks$Prop[^[:alnum:]]}
DbLayer=${DbLayerNext%%$'\n'$Blocks[^ ]*}
done
printf '%s' "$DbLayer"
}
Both give the same result:
echo "$(BAAM "$MY_DATA" SpaceX links website)"
But will it run Crysis?
No.
This speed test grabs the website of SpaceX from the dataset and puts it in a variable 50,000 times.
for value in {1..50000}; do
Val=$(BAAM "$MY_DATA" SpaceX links website)
done
Results
Old version using PCRE:
(I removed the new lines before the loop to make things as fast as possible)
Run 1: 2m39.959s
Run 2: 2m40.426s
Run 3: 2m40.119s
New version using pure BASH:
Run 1: 41.188s
Run 2: 39.975s
Run 3: 39.628s
Conclusions
Same number of lines, less code and 5x faster at 1,250 lookups per second.
I tried exchanging the last line of the old version for the Perl solution but it increased times to 3m26s.
perl -e "'$1' =~ m/$REGEX_STR/s; print $&;"
This project is now firmly on the road to an elegant pure BASH solution.