URL decoding with awk

The challenge:

Decode URL's, i.e. convert %HEX to the corresponding special characters, using only UNIX base utilities, and without having to type out each special character.

I have an anonymous C code snippet where the author assigns each hex digit a number from 0 to 16 and then does some bit shifting. It works nicely.

Is there an easy way to do this with awk?

Wanna see an ugly hack? Well, here it is anyway. This attempt outputs a shell function called "ud" that purports to decode URL's piped through it. Not tested thoroughly.

Maybe this could be done with dc or bc (for hex->octal, then use awk for gsub) instead of xxd.

_ud(){
{
jot -w"printf '\%03d'|xxd -u" 178 000 177|sh ;
jot -w"printf '\%03d'|xxd -u" 178 000 177|sh\
 |dd conv=lcase 2>&- ;
} \
 |sed -e '
s/.*0: //;
/[A-Za-z0-9]$/d;
/^[01]/d;' \
 -e ':a' \
 -e 's/  / /;t a' \
 -e '
s, ,l,;
s,.*,sl%&lg,;
/2[Ff]/!s,ll,l+l,;
/5[Cc]/s,.,\"&\",7;
/22/s,\",\\",;
/26/s,&,\\&,;
/27/d;
' 
printf 'sl%%27l\047\"\047\"\047lg\n';
printf 's/&/\&/g\n'
}

ud(){
_ud \
 |sed '
1s,.*,ud(){\
sed '"'"'\
&,;
$s,.*,&\
'"'"';\
},
'

} 

Yikes!

What's your system? What's your shell?

I'd try converting %02 into \x02, then feeding it through echo -e, but that's a Linux/BASH thing...

I had another go at this without using xxd.

This version uses only sh builtins, sed, jot/seq and dc.

Not thoroughly tested, but seems to work.

Handling unicode too would be useful.

# octal to hex #
o2h(){ 
echo 16o 8i $1 p|dc;
}

# print an ascii table #
ud1(){ 
{
case $(uname) in 
FreeBSD)
jot -w%03d 178 000 177;
\
 ;;
*)
seq -w 000 177;
\
 ;;
esac;
} \
 |while read a;do 
printf '\'$a'\040'$a'\n' ;
done \
 |sed '
1,/039/d;
/[89]$/d;
/[89].$/d;
$d;
/^ /s/ /+/;
/^$/d;
'

}

# rough sed script to fd1 #
ud2(){
sed 's,.* ,,' \
| while read a;
do 
printf 'sl%%';
printf $(o2h $a);
printf 'l'
printf '\'$a;
printf 'lg\n';
done;
}

# add escapes or quotes \
 # for certain specials chars \
 # and delete single quote hex 27 #
ud3(){
sed '
/20/s/ /+/;
/6C/{
s,l,/,;
s,ll,/l,;
s,lg,/g,;
};
/5C/s,.,\"&\",7;
/22/s,\",\\",;
/26/s,&,\\&,;
/27/d;
';
}

# add single quote hex 27 #
ud4(){
printf 'sl%%27l\047\"\047\"\047lg\n';
}

# function header #
ud5(){
echo "ud(){
sed '";
}

# function footer #
ud6(){
echo "'
}"
}

# put it all together #
ud7(){ 
{
ud5;
ud1 \
 |ud2 \
 |ud3;
ud4;
ud6;
};
}