As answered on askubuntu you could run some Python code.
# To encode:
python -c "import urllib, sys; print urllib.quote(sys.argv[1])" "String to encode"
# To decode:
python -c "import urllib, sys; print urllib.unquote(sys.argv[1])" "String%20to%20encode"
# Or if you have Python 3.x installed you could use these:
python3 -c "from urllib.parse import quote, sys; print(quote(sys.argv[1]))" "String to encode"
python3 -c "from urllib.parse import unquote, sys; print(unquote(sys.argv[1]))" "String%20to%20encode"
As for the bonus 2 there is no need for percentage-encoding anything in the fragment identifier, but if you would like to encode those as well, you could use the above and pipe the output to this sed command:
sed 's/%23/#/' # Replace the first percentage-encoded hashtag with a hashtag
Note: The above commands will encode the whole url to percentage-encoding, so keep in mind that including the protocol will encode the colon and possibly the question mark in marking the beginning of the query string. The commands where only ever intended to percentage-encode query strings and path names in URLs. You could omit these problems by using the above sed command to replace the unwanted percentage encoded characters.
If you want to be able to run this as a single command with the string to be encoded/decoded I suppose there's already something out there. If not, you could take this python code and include it in a python program or bash script.