How can I encode and decode percent-encoded strings on the command line?

How can I encode and decode percent-encoded (URL encoded) strings on the command line?

I’m looking for a solution that can do this:

$ percent-encode "ændrük"
$ percent-decode "%C3%A6ndr%C3%BCk"

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

These commands do what you want (using Python 2):

python -c "import urllib, sys; print urllib.quote(sys.argv[1])" æ
python -c "import urllib, sys; print urllib.unquote(sys.argv[1])" %C3%A6

If you want to encode spaces as +, replace urllib.quote with urllib.quote_plus.

I’m guessing you will want to alias them 😉

Solution 2


Try the following command line:

$ echo "%C3%A6ndr%C3%BCk" | sed '[email protected][email protected] @g;[email protected]%@\\[email protected]' | xargs -0 printf "%b"

You may define it as alias and add it to your shell rc files:

$ alias urldecode='sed "[email protected][email protected] @g;[email protected]%@\\\\[email protected]" | xargs -0 printf "%b"'

Then every time when you need it, simply go with:

$ echo "http%3A%2F%2Fwww" | urldecode


When scripting, you can use the following syntax:

decoded=$(printf '%b' "${input//%/\\x}")

However above syntax won’t handle pluses (+) correctly, so you’ve to replace them with spaces via sed.

You can also use the following urlencode() and urldecode() functions:

urlencode() {
    # urlencode <string>
    local length="${#1}"
    for (( i = 0; i < length; i++ )); do
        local c="${1:i:1}"
        case $c in
            [a-zA-Z0-9.~_-]) printf "$c" ;;
            *) printf '%%%02X' "'$c"

urldecode() {
    # urldecode <string>

    local url_encoded="${1//+/ }"
    printf '%b' "${url_encoded//%/\\x}"

Note that your urldecode() assumes the data contains no backslash.

bash + xxd

Bash function with xxd tool:

urlencode() {
  local length="${#1}"
  for (( i = 0; i < length; i++ )); do
    local c="${1:i:1}"
    case $c in
      [a-zA-Z0-9.~_-]) printf "$c" ;;
    *) printf "$c" | xxd -p -c1 | while read x;do printf "%%%s" "$x";done

Found in cdown’s gist file, also at stackoverflow.


Try to define the following aliases:

alias urldecode='python -c "import sys, urllib as ul; print ul.unquote_plus(sys.argv[1])"'
alias urlencode='python -c "import sys, urllib as ul; print ul.quote_plus(sys.argv[1])"'


$ urlencode "ændrük"
$ urldecode "%C3%A6ndr%C3%BCk"

Source: ruslanspivak


Using PHP you can try the following command:

$ echo oil+and+gas | php -r 'echo urldecode(fgets(STDIN));' // Or: php://stdin
oil and gas

or just:

php -r 'echo urldecode("oil+and+gas");'

Use -R for multiple line input.


In Perl you can use URI::Escape.

decoded_url=$(perl -MURI::Escape -e 'print uri_unescape($ARGV[0])' "$encoded_url")

Or to process a file:

perl -i -MURI::Escape -e 'print uri_unescape($ARGV[0])' file


Using sed can be achieved by:

cat file | sed -e's/%\([0-9A-F][0-9A-F]\)/\\\\\x\1/g' | xargs echo -e


Try anon solution:

awk -niord '{printf RT?$0chr("0x"substr(RT,2)):$0}' RS=%..

See: Using awk printf to urldecode text.

decoding file names

If you need to remove url encoding from the file names, use deurlname tool from renameutils (e.g. deurlname *.*).

See also:


Solution 3

Percent-encode reserved URI characters and non-ASCII characters

jq -s -R -r @uri

-s (--slurp) reads input lines into an array and -s -R (--slurp --raw-input) reads the input into a single string. -r (--raw-output) outputs the contents of strings instead of JSON string literals.

Percent-encode all characters

xxd -p|tr -d \\n|sed 's/../%&/g'

tr -d \\n removes the linefeeds that are added by xxd -p after every 60 characters.

Percent-encode all characters except ASCII alphanumeric characters in Bash

eu () {
    local LC_ALL=C c
    while IFS= read -r -n1 -d '' c
        if [[ $c = [[:alnum:]] ]]
            printf %s "$c"
            printf %%%02x "'$c"

Without -d '' this would skip linefeeds and null bytes. Without IFS= this would replace characters in IFS with %00. Without LC_ALL=C this would for example replace with %3042 in a UTF-8 locale.

Solution 4

Pure bash solution for decoding only:

$ a='%C3%A6ndr%C3%BCk'
$ echo -e "${a//%/\\x}"

Solution 5

I can’t comment on best answer in this thread, so here is mine.

Personally, I use these aliases for URL encoding and decoding:

alias urlencode='python -c "import urllib, sys; print urllib.quote(  sys.argv[1] if len(sys.argv) > 1 else[0:-1])"'

alias urldecode='python -c "import urllib, sys; print urllib.unquote(sys.argv[1] if len(sys.argv) > 1 else[0:-1])"'

Both commands allow you to convert data, passed as a command line argument or read it from standard input, because both one-liners check whether there are command line arguments (even empty ones) and process them or just read standard input otherwise.

update 2015-07-16 (empty 1st arg)

… according to @muru comment.

update 2017-05-28 (slash encoding)

If you also need to encode the slash, just add an empty second argument to the quote function, then the slash will also be encoded.

So, finally urlencode alias in bash looks like this:

alias urlencode='python -c "import urllib, sys; print urllib.quote(sys.argv[1] if len(sys.argv) > 1 else[0:-1], \"\")"'


$ urlencode "Проба пера/Pen test"

$ echo "Проба пера/Pen test" | urlencode

$ urldecode %D0%9F%D1%80%D0%BE%D0%B1%D0%B0%20%D0%BF%D0%B5%D1%80%D0%B0%2FPen%20test
Проба пера/Pen test

$ echo "%D0%9F%D1%80%D0%BE%D0%B1%D0%B0%20%D0%BF%D0%B5%D1%80%D0%B0%2FPen%20test" | urldecode
Проба пера/Pen test

$ urlencode "Проба пера/Pen test" | urldecode
Проба пера/Pen test

$ echo "Проба пера/Pen test" | urlencode | urldecode
Проба пера/Pen test

Solution 6

Similar to Stefano ansqer but in Python 3:

python3 -c "import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))" æ         # to percent-enconding
python3 -c "import urllib.parse, sys; print(urllib.parse.unquote(sys.argv[1]))" %C3%A6  # from percent-enconding

To encode also slashes:

python3 -c "import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1] if len(sys.argv) > 1 else[0:-1], \"\"))"

More info about the difference here.

Solution 7

I found a package, renameutils, that contain the utility deurlname that is able to rename a file containing “percent-encoded” characters.

Unfortunately, it does not decode stdin or a command line option, but only rename a file, so you have to create a dummy file to obtain the decoding (the name of the renamed file), but with some bash scripting the process can be automated.

No information about the encoding part, even because it could be questionable which characters to encode. Only non-ASCII?

I think there should be some better tool/method.

Solution 8

Here is a POSIX Awk function for encoding:

function encodeURIComponent(str, j, q) {
  while (y++ < 125) z[sprintf("%c", y)] = y
  while (y = substr(str, ++j, 1))
    q = y ~ /[[:alnum:]_.!~*\47()-]/ ? q y : q sprintf("%%%02X", z[y])
  return q


Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply