Elifarley
Elifarley

Reputation: 1420

URL encoding a string in shell script in a portable way

I need to URL encode a string using a shell function that will run in BusyBox Ash, Dash, Bash and ZSH.

It will run in different Docker containers, so it'd be good to have as little dependencies to install as possible.

Notes:

What I'd expect to have:

$> urlencode '/'
%2f

$> urlencode 'ç'
%c3%a7

$> urlencode '*'
%2a

$> urlencode abc-123~6
abc-123~6

$> urlencode 'a test ?*ç '
a%20test%20%3f%2a%c3%a7%20

Upvotes: 2

Views: 8292

Answers (1)

Elifarley
Elifarley

Reputation: 1420

The functions below have been tested in BusyBox Ash, Dash, Bash and ZSH.

They only use shell builtins or core commands and should work in other shells as well.

urlencodepipe() {
  local LANG=C; local c; while IFS= read -r c; do
    case $c in [a-zA-Z0-9.~_-]) printf "$c"; continue ;; esac
    printf "$c" | od -An -tx1 | tr ' ' % | tr -d '\n'
  done <<EOF
$(fold -w1)
EOF
  echo
}

urlencode() { printf "$*" | urlencodepipe ;}

How it works:

  • Standard input is processed by fold -w1, which re-formats its input so that it is 1 column wide (in other words, it adds a \n after each input character so that each character will be on its own line)
  • The here-document <<EOF feeds the output of fold to the read command
  • The while command accepts one line at a time (which is only 1 character wide) from the read command, which gets its input from fold, and assigns it to variable c
  • case tests if that character needs to be url encoded. If it doesn't, then it's printed and the while loop continues
  • od converts each input character to hex
  • tr converts spaces to % and joins multiple lines

Upvotes: 6

Related Questions