Skip to content

Instantly share code, notes, and snippets.

@1480c1
Last active December 29, 2022 03:08
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 1480c1/455c0ec47cd5fd0514231ba865f0fca0 to your computer and use it in GitHub Desktop.
Save 1480c1/455c0ec47cd5fd0514231ba865f0fca0 to your computer and use it in GitHub Desktop.
posix shell urlencode and urldecode that handles multiline strings from both stdin and from arguments
urlencode() (
string=${*:-$(
cat -
printf x
)}
[ -n "$*" ] || string=${string%x}
# Zero index, + 1 to start from 1 since sed starts from 1
lines=$(($(printf %s "$string" | wc -l) + 1))
lineno=1
while [ $lineno -le $lines ]; do
currline=$(printf %s "$string" | sed "${lineno}q;d")
pos=1
chars=$(printf %s "$currline" | wc -c)
while [ $pos -le "$chars" ]; do
c=$(printf %s "$currline" | cut -b$pos)
case $c in
[-_.~a-zA-Z0-9]) printf %c "$c" ;;
*) printf %%%02X "'${c:-\n}'" ;;
esac
pos=$((pos + 1))
done
[ $lineno -eq $lines ] || printf %%0A
lineno=$((lineno + 1))
done
)
urldecode() {
string=${*:-$(
cat -
printf x
)}
[ -n "$*" ] || string=${string%x}
# Zero index, + 1 to start from 1 since sed starts from 1
lines=$(($(printf %s "$string" | wc -l) + 1))
lineno=1
while [ $lineno -le $lines ]; do
currline=$(printf %s "$string" | sed "${lineno}q;d")
pos=1
chars=$(printf %s "$currline" | wc -c)
while [ $pos -le "$chars" ]; do
c=$(printf %s "$currline" | cut -b$pos)
case $c in
\+) printf ' ' ;;
%)
# shellcheck disable=SC2059
printf "$(
printf '\\%03o' "$(
printf %s "$currline" | cut -b$pos-$((pos + 2)) | sed s/%/0x/
)"
)"
pos=$((pos + 2))
;;
*) printf %c "$c" ;;
esac
pos=$((pos + 1))
done
[ $lineno -eq $lines ] || printf '\n'
lineno=$((lineno + 1))
done
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment