Tengo un archivo con una lista de los agentes de usuario que están codificados.
E. g.:

Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en

Quiero un script de shell que puede leer este archivo y escribir en un archivo nuevo con decodificado cadenas.

Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en

He estado tratando de utilizar este ejemplo para ponerlo en marcha, pero no es trabajo hasta el momento.

$ echo -e "$(echo "%31+%32%0A%33+%34" | sed 'y/+//; s/%/\x/g')"

Mi script parece:

#!/bin/bash
for f in *.log; do
  echo -e "$(cat $f | sed 'y/+//; s/%/\x/g')" > y.log
done
  • línea 5: «x» debe ser el doble de escape (s/%/\x/g -> s/%/\\x/g
  • Gracias por el puntero. Tratará con doble escape. No sé cómo me lo perdí cuando me lo copió de algún otro lugar. Se actualizará.
  • unix.stackexchange.com/questions/159253/…
InformationsquelleAutor user785717 | 2011-06-06

18 Comentarios

  1. 41

    Aquí es una simple línea de solución.

    $ urldecode() { : "${*//+/}"; echo -e "${_//%/\x}"; }

    Se puede ver como perl 🙂 pero es sólo pura bash. No awks, no hay sed … no de los gastos generales. El uso de la : builtin, los parámetros especiales, patrón de sustitución y el eco builtin la opción-e para traducir los códigos hexadecimales en los personajes. Ver página del manual de bash para más detalles. Usted puede utilizar esta función como comando independiente

    $ urldecode https%3A%2F%2Fgoogle.com%2Fsearch%3Fq%3Durldecode%2Bbash
    https://google.com/search?q=urldecode+bash

    o en asignaciones de variables, así:

    $ x="http%3A%2F%2Fstackoverflow.com%2Fsearch%3Fq%3Durldecode%2Bbash"
    $ y=$(urldecode "$x")
    $ echo "$y"
    http://stackoverflow.com/search?q=urldecode+bash
    • Su ejemplo no funciona: ` la línea 3: urldecode: comando no encontrado»
    • El amor de algo más de explicación sobre el patrón de sustitución. Esta función funciona para mí, pero los cambios de los personajes de una manera que hace que las rutas de archivo no funciona con el descomprima función.
    • reemplazará todo + con el espacio y ${_//%/\\x} reemplazará todo % con \x.
    • sólo quiero mencionar que esto es horriblemente lento para mí; por 50k url, bash: 0m3.767s python: 0m0.200s (python uno forro a continuación: stackoverflow.com/a/21693459/1695680)
  2. 18

    GNU awk

    #!/usr/bin/awk -fn
    @include "ord"
    BEGIN {
      RS = "%.."
    }
    {
      printf RT ? $0 chr("0x" substr(RT, 2)) : $0
    }

    O

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

    El uso de awk printf para urldecode texto

    • una línea! muy bueno thx!
    • Lamentablemente no funciona con patológico cadenas que contienen, dicen, guiones y urlencoded el signo.
    • Desgraciadamente esto funciona exclusivamente en GNU awk, mientras que en un par de comerciales awk implementaciones, esta función chr() no está disponible. Por CIERTO, también se puede omitir el --include|-i declaración y uso @load "ordchr" directamente en el código. (encontrar a través de RTFM ;-))
  3. 11

    Esto es lo que parece estar funcionando para mí.

    #!/bin/bash
    urldecode(){
      echo -e "$(sed 's/+//g;s/%\(..\)/\x/g;')"
    }
    
    for f in /opt/logs/*.log; do
        name=${f##/*/}
        cat $f | urldecode > /opt/logs/processed/$HOSTNAME.$name
    done

    Sustitución de ‘+’s con los espacios y los signos % con ‘\x’ se escapa, y dejar que el echo de interpretar el \x escapa el uso de la ‘-e’ opción no estaba funcionando. Por alguna razón, el comando cat fue la impresión que el signo % como su propia forma codificada %25. Así que sed fue simplemente reemplazando %25 con \x25. Cuando la opción-e utilizada, era simplemente la evaluación de \x25 como % y el resultado fue el mismo que el original.

    De seguimiento:

    Original: Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en

    sed: Mozilla\x252F5.0\x2520\x2528Macintosh\x253B\x2520U\x253B\x2520Intel\x2520Mac\x2520OS\x2520X\x252010.6\x253B\x2520en

    echo-e: Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en

    Revisión: Básicamente ignorar los 2 caracteres después de que el % de sed.

    sed: Mozilla\x2F5.0\x20\x28Macintosh\x3B\x20U\x3B\x20Intel\x20Mac\x20OS\x20X\x2010.6\x3B\x20en

    echo-e: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en

    No está seguro de cuáles son las complicaciones que esto podría resultar en, después de extensas pruebas, pero funciona por ahora.

    • Funciona, pero no debe ser un \1 después de \\x como echo -e "$(sed 's/+/ /g;s/%\(..\)/\\x\1/g;')"
    • Como @svante escribió, el \1 falta. He editado la respuesta a incluir. (Además de un par de pequeño formato/gramática cambios para cumplir con la de 6 caracteres mínimo editar requisito).
  4. 11

    Con BASH, para leer el por ciento de dirección URL codificada de estándar y decodificar:

    while read; do echo -e ${REPLY//%/\x}; done

    Pulse CTRLD para indicar el final del archivo(EOF) y salir correctamente.

    Puede descodificar el contenido de un archivo de configuración el archivo a ser la norma en:

    while read; do echo -e ${REPLY//%/\x}; done < file

    Puede decodificar la entrada de una tubería, ya sea, por ejemplo:

    echo 'a%21b' | while read; do echo -e ${REPLY//%/\x}; done
    • La lectura, construido en el comando lee estándar hasta que se ve un carácter de avance de Línea. Se establece una variable llamada REPLY igual a la línea de texto que acaba de leer.
    • ${REPLY//%/\\x} reemplaza todas las instancias de ‘%’ con ‘\x’.
    • echo -e interpreta \xNN como el carácter ASCII con el valor hexadecimal de NN.
    • mientras repite este ciclo hasta que el comando de lectura falla, por ejemplo. EF ha sido alcanzado.

    El de arriba no cambia ‘+’ a ‘ ‘. A cambio de ‘+’ a » también, como invitado del respuesta:

    while read; do : "${REPLY//%/\x}"; echo -e ${_//+/ }; done
    • : es un BASH integrados de comando. Aquí sólo se necesita en un único argumento y no hace nada con ella.
    • De las comillas dobles hacer todo dentro de un solo parámetro.
    • _ es un parámetro especial que es igual que el último argumento del comando anterior, después de que el argumento de expansión. Este es el valor de REPLY con todas las instancias de ‘%’ reemplazado con ‘\x’.
    • ${_//+/} reemplaza todas las instancias de ‘+’ con ‘ ‘.

    Este solo usa BASH y no se inicia otro proceso, similar a la respuesta del huésped.

    • Esto es genial.
  5. 10

    si usted es un python desarrollador, esto tal vez preferer

    echo "%21%20" | python -c "import sys, urllib as ul; print ul.unquote(sys.stdin.read());"

    urllib es profesional en el manejo

    • Bueno, pero me gustaría cambiar un poco el uso de argv y el uso es como un alias. Aquí es un ejemplo para la codificación de: alias de codificar=’python2 -c «import sys, urllib como ul; la impresión de ul.cita(sys.argv[1]);»‘
    • Modificado para python 3: echo "%21%20" | python -c "import sys; from urllib.parse import unquote; print(unquote(sys.stdin.read()));"
  6. 7
    perl -pi.back -e 'y/+//;s/%([\da-f]{2})/pack H2,$1/gie' ./*.log

    Con -i las actualizaciones de los archivos en su lugar (algunos sed las implementaciones han prestado, que desde perl) con .back como la extensión de copia de seguridad.

    s/x/y/e sustitutos x con el evaloración de la y código perl.

    El código perl en este caso utiliza pack para empacar el número hexadecimal capturado en $1 (primer par de paréntesis en la regexp) como el carácter correspondiente.

    Una alternativa a pack es el uso de chr(hex($1)):

    perl -pi.back -e 'y/+//;s/%([\da-f]{2})/chr hex $1/gie' ./*.log

    Si está disponible, también se podría utilizar uri_unescape() de URI::Escape:

    perl -pi.back -MURI::Escape -e 'y/+//;$_=uri_unescape$_' ./*.log
    • Este ejemplo sería aún mejor con un par de palabras de explicación.
  7. 6

    Script de Bash para hacerlo en el nativo de Bash (fuente original):

    LANG=C
    
    urlencode() {
        local l=${#1}
        for (( i = 0 ; i < l ; i++ )); do
            local c=${1:i:1}
            case "$c" in
                [a-zA-Z0-9.~_-]) printf "$c" ;;
                ' ') printf + ;;
                *) printf '%%%.2X' "'$c"
            esac
        done
    }
    
    urldecode() {
        local data=${1//+/ }
        printf '%b' "${data//%/\x}"
    }

    Si quieres urldecode contenido del archivo, sólo hay que poner el contenido del archivo como argumento.

    He aquí una prueba de que se ejecute detener si el decodificado de archivo codificado el contenido difiere (si se ejecuta durante un par de segundos, la secuencia de comandos probablemente funciona correctamente):

    while true
      do cat /dev/urandom | tr -d '
    while true
    do cat /dev/urandom | tr -d '\0' | head -c1000 > /tmp/tmp;
    A="$(cat /tmp/tmp; printf x)"
    A=${A%x}
    A=$(urlencode "$A")
    urldecode "$A" > /tmp/tmp2
    cmp /tmp/tmp /tmp/tmp2
    if [ $? != 0 ]
    then break
    fi
    done
    '
    | head -c1000 > /tmp/tmp; A="$(cat /tmp/tmp; printf x)" A=${A%x} A=$(urlencode "$A") urldecode "$A" > /tmp/tmp2 cmp /tmp/tmp /tmp/tmp2 if [ $? != 0 ] then break fi done
    • Tenga en cuenta que su urldecode supone que los datos no contiene una barra invertida.
    • Creo barras diagonales inversas no son permitidos en la correcta %cadenas codificadas
  8. 4

    Como @barti_ddu dijo en los comentarios, \x «debería ser [doble]se escapó».

    % echo -e "$(echo "Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en" | sed 'y/+//; s/%/\x/g')"
    Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en

    Lugar de la mezcla de Bash y sed, me gustaría hacer todo esto en Python. He aquí un corte brusco de cómo:

    #!/usr/bin/env python
    
    import glob
    import os
    import urllib
    
    for logfile in glob.glob(os.path.join('.', '*.log')):
        with open(logfile) as current:
            new_log_filename = logfile + '.new'
            with open(new_log_filename, 'w') as new_log_file:
                for url in current:
                    unquoted = urllib.unquote(url.strip())
                    new_log_file.write(unquoted + '\n')
    • Gracias por el script. Le dará la sed versión de una oportunidad más y tomar el python ruta si se produce un error. He leído que la sed enfoque fue más rápido. Es que es verdad. Voy a tener un par de GB de tamaño de los archivos de proceso por cada hora y se puede utilizar toda la ventaja.
    • Esperemos que funcione para usted. Yo no tengo ni idea de lo que tendrá un mejor desempeño en sus datos. time es tu amigo.
    • Por qué?
  9. 3

    Con GNU awk:

    gawk -vRS='%[0-9a-fA-F]{2}' 'RT{sub("%","0x",RT);RT=sprintf("%c",strtonum(RT))}
                                 {gsub(/\+/," ");printf "%s", $0 RT}'
  10. 2

    Aquí es una solución que se realiza en el más puro bash donde de entrada y de salida son las variables bash. Se descifrará ‘+’ como un espacio y manejar la ‘%20’ del espacio, así como otros %-caracteres codificados.

    #!/bin/bash
    #here is text that contains both '+' for spaces and a %20
    text="hello+space+1%202"
    decoded=$(echo -e `echo $text | sed 's/+//g;s/%/\\x/g;'`)
    echo decoded=$decoded
    • sed no es pura Bash; esto genera otro proceso.
  11. 2
    $ uenc='H%C3%B6he %C3%BCber%20dem%20Meeresspiegel'
    $ utf8=$(echo -e "${uenc//%/\x}")
    $ echo $utf8
    Höhe über dem Meeresspiegel
    $
    • Por favor envíe una explicación, no sólo de código.
    • Aunque este código puede responder a la pregunta, proporcionar contexto adicional sobre porque y/o como contesta a la pregunta podría mejorar significativamente su valor de largo plazo. Por favor, editar su respuesta a añadir un poco de explicación.
  12. 2

    Actualización Jay respuesta para Python 3.5+:

    echo "%31+%32%0A%33+%34" | python -c "import sys; from urllib.parse import unquote ; print(unquote(sys.stdin.read()))"

    Todavía, brendan bash solución con la explicación parece más directo y elegante.

  13. -1

    Frente a un problema similar, mi idea inicial era utilizar urldecode de PHP en un script que lee de stdin o algunos-tal, pero luego me encontré con esta idea. Todas las respuestas parecen tener una gran cantidad de texto, pero no presentan ninguna solución real. La idea es que el sonido, sin embargo, y muy fácil conseguir trabajo:

    $ mpc | sed -e '1! d'
    http://e.org/play.php?name=/Black%20Sun%20Empire%20-%20Sideways%20%28Feat.%20Illy%20Emcee%29
    
    $ basename "$(echo -e `mpc | sed -e '1! d' -e 's/%/\\x/g'`)"
    Black Sun Empire - Sideways (Feat. Illy Emcee)

    La clave para hacer que funcione es de doble escape \x (esto ha sido mencionado ya).

  14. -1

    Sólo quería compartir esta otra solución, puro bash:

    encoded_string="Mozilla%2F5.0%20%28Macintosh%3B%20U%3B%20Intel%20Mac%20OS%20X%2010.6%3B%20en"
    printf -v encoded_string "%b" "${encoded_string//\%/\x}"
    echo $encoded_string
  15. -1

    Una versión ligeramente modificada de la de Python respuesta que acepta una entrada y una salida en un archivo de uno forro.

    cat inputfile.txt | python -c "import sys, urllib as ul; print ul.unquote(sys.stdin.read());" > ouputfile.txt
  16. -3
    $ uenc='H%C3%B6he %C3%BCber%20dem%20Meeresspiegel'
    $ utf8=$(printf "${uenc//%/\x}")
    $ echo $utf8
    Höhe über dem Meeresspiegel
    $
    • Aunque este código puede responder a la pregunta, proporcionar contexto adicional sobre porque y/o como contesta a la pregunta podría mejorar significativamente su valor de largo plazo. Por favor, editar su respuesta a añadir un poco de explicación.

Dejar respuesta

Please enter your comment!
Please enter your name here