Skip to content

Instantly share code, notes, and snippets.

@hyperupcall
Created December 12, 2021 10:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hyperupcall/326289788985d8fdf672ecb362242303 to your computer and use it in GitHub Desktop.
Save hyperupcall/326289788985d8fdf672ecb362242303 to your computer and use it in GitHub Desktop.
Hacky lookahead / peek with `read -N1`
# shellcheck shell=bash
# Caveat: Only one start_peek can be ran for any particular case block
start_peek() {
if [ "$peek_status" = not_peeking ]; then
peek_status='currently_peeking'
peek_current=0
peek_total="$1"
REPLY_PEEKED_CHARACTERS="$2"
# Return true, so the conditional after 'lookahead_char' is ran.
# The conditional must have 'continue'
return 0
elif [ "$peek_status" = currently_peeking ]; then
# This shouldn't fire due to the 'continue' statement
:
elif [ "$peek_status" = done_peeking ]; then
REPLY_PEEKED_CHARACTERS="${REPLY_PEEKED_CHARACTERS#?}"
peek_status='not_peeking'
return 1
fi
}
# Use separate variable 'REPLY_LOOKAHEAD' since 'REPLY' could be clobbered by something else
peek_status='not_peeking'
peek_total=
peek_current=
parse_char() {
local char="$1"
echo "current char: '$char'"
case "$char" in
\ )
if start_peek 3 \ ; then
return
fi
# remember output is correct. two occurenced of current char: ' '
# Since lookaheads don't gobble the input stream, one print is when we do
# the lookahead, and the second one is here, where we finish the peek
echo "start_peek 3 result: '$REPLY_PEEKED_CHARACTERS'"
;;
\{)
:
;;
esac
}
string1="key =fourd"
echo "original string: '$string1"
# shellcheck disable=SC2059
while IFS= read -rN1 char; do
if [ "$peek_status" = currently_peeking ] ; then
if ((peek_current < peek_total)); then
REPLY_PEEKED_CHARACTERS+="$char"
peek_current=$((peek_current+1))
continue
elif ((peek_current == peek_total)); then
REPLY_PEEKED_CHARACTERS+="$char"
peek_current=$((peek_current+1))
fi
peek_status='done_peeking'
while IFS= read -rN1 char; do
parse_char "$char"
done < <(printf "$REPLY_PEEKED_CHARACTERS")
continue
fi
parse_char "$char"
done < <(printf "$string1")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment