Skip to content

Commit 3688f01

Browse files
committed
Improve parsing speed by avoiding grep forks.
Signed-off-by: Kurt Garloff <kurt@garloff.de>
1 parent ddbefc0 commit 3688f01

1 file changed

Lines changed: 46 additions & 11 deletions

File tree

yaml_parse.sh

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,43 @@
44
# We do some (incomplete) YAML parsing in bash as helper to 04-cloud-secret.sh
55
# to extract and construct a conforming clouds.yaml with exactly one
66
# openstack entry.
7-
# This is SLOW by walking a file line by line, using several grep calls per line,
8-
# which is a fork.
9-
# Could be optimized by doing the simple things in bash, but this is not urgent.
7+
# This used to be SLOW by using several grep calls (forks) per line.
8+
# Optimized a bit using three helpers; still going line by line in bash, so expect
9+
# 2s for 1000 lines of clouds.yaml or so.
1010
#
1111
# (c) Kurt Garloff <s7n@garloff.de>, 5/2025
1212
# SPDX-License-Identifier: CC-BY-SA-4.0
13-
#
13+
14+
# linestart detection
15+
# $1: linestart to look for
16+
# $2: string to search in
17+
startswith()
18+
{
19+
case "$2" in
20+
"$1"*)
21+
return 0;;
22+
esac
23+
return 1
24+
}
25+
26+
# emptyline helper
27+
# $1: line
28+
islineempty()
29+
{
30+
local LN
31+
IFS=" " read LN < <(echo "$1")
32+
if test -z "$LN"; then return 0; else return 1; fi
33+
}
34+
35+
# comment helper
36+
# $1: line
37+
islinecomment()
38+
{
39+
local LN
40+
IFS=" " read LN < <(echo "$1")
41+
if test "${LN:0:1}" = "#"; then return 0; else return 1; fi
42+
}
43+
1444
# Helper: Parse YAML (recursive)
1545
#
1646
# We take two parameters
@@ -36,17 +66,20 @@ extract_yaml_rec()
3666
while IFS="" read line; do
3767
let LNNO+=1
3868
# Ignore empty lines
39-
if echo "$line" | grep '^\s*$' >/dev/null 2>&1; then continue; fi
69+
#if echo "$line" | grep -q '^\s*$'; then continue; fi
70+
if islineempty "$line"; then continue; fi
4071
# First line of new block: We need more indentation ...
4172
if test "$more" = "1"; then
42-
if ! echo "$line" | grep "^$previndent\s" >/dev/null 2>&1; then return; fi
73+
if ! echo "$line" | grep -q "^$previndent\s"; then return; fi
4374
more=$(echo "$line" | sed "s/^$previndent\\(\s*\\)[^\s].*\$/\\1/")
4475
#echo "$previndent$more# $LNNO: New indent level"
4576
fi
4677
# Detect less indentation than wanted, return
47-
if ! echo "$line" | grep "^$previndent$more" >/dev/null 2>&1; then return; fi
78+
#if ! echo "$line" | grep -q "^$previndent$more"; then return; fi
79+
if ! startswith "$previndent$more" "$line"; then return; fi
4880
# Strip comments if requested
49-
if test -n "$RMVCOMMENT" && echo "$line" | grep '^\s*#' >/dev/null 2>&1; then continue; fi
81+
#if test -n "$RMVCOMMENT" && echo "$line" | grep -q '^\s*#'; then continue; fi
82+
if test -n "$RMVCOMMENT" && islinecomment "$line"; then continue; fi
5083
# OK, we we have at least the indentation level needed
5184
# 3 cases:
5285
# (a) We are prior to finding the right block, continue searching
@@ -58,21 +91,23 @@ extract_yaml_rec()
5891
# got here, just output until the less indentation clause above indicates the end
5992
if test -z "$1"; then
6093
#echo "$previndent$more# $LNNO: Outputing block"
61-
if test -z "$REMOVE" || ! echo "$line" | grep "^$previndent$more$REMOVE:" >/dev/null 2>&1; then
94+
#if test -z "$REMOVE" || ! echo "$line" | grep -q "^$previndent$more$REMOVE:"; then
95+
if test -z "$REMOVE" || ! startswith "$previndent$more$REMOVE:" "$line"; then
6296
echo "$line"
6397
fi
6498
continue
6599
fi
66100
# b2: Search for the keyword
67-
if echo "$line" | grep "^$previndent$more$1:" >/dev/null 2>&1; then
101+
#if echo "$line" | grep -q "^$previndent$more$1:"; then
102+
if startswith "$previndent$more$1:" "$line"; then
68103
#echo "$previndent$more# $LNNO: Found keyword $1"
69104
# Output tree unless we suppress it
70105
if test -z "$RMVTREE"; then
71106
echo "$line"
72107
else
73108
# At the leaf, we may hold a value
74109
if test -z "$2"; then
75-
echo "$line" | grep --color=never "^$previndent$more$1: [^\\s]" 2>/dev/null
110+
echo "$line" | grep --color=never "^$previndent$more$1: [^\\s]"
76111
fi
77112
fi
78113
shift

0 commit comments

Comments
 (0)