Cómo grep para unicode en un script bash

10
if grep -q "�" out.txt
    then
        echo "working"
    else
        cat out.txt
fi

Básicamente, si el archivo "out.txt" contiene " " en cualquier parte del archivo, me gustaría que haga eco de "trabajo" Y si el archivo "out.txt" NO contiene " " en ningún lugar del archivo, me gustaría a cat out.txt

EDITAR: Entonces, esto es lo que estoy haciendo. Estoy tratando de forzar a un descifrado de OpenSL.

openssl enc devuelve 0 en caso de éxito, de lo contrario no es cero. Nota: obtendrá falsos positivos porque AES / CBC solo puede determinar si el "descifrado funciona" en función del correcto relleno. Por lo tanto, el archivo se descifra pero no será la contraseña correcta, por lo que tendrá galimatías. Un personaje común en el galimatías es " ". Entonces, quiero que el bucle do continúe si la salida contiene " ".

Aquí está mi enlace git https://github.com/Raphaeangelo/OpenSSLCracker Aquí está el script

while read line
do
openssl aes-256-cbc -d -a -in $1 -pass pass:$line -out out.txt 2>out.txt >/dev/null && printf "==================================================\n"
if grep -q "�" out.txt
    then
        :
    else
        cat out.txt &&
            printf "\n==================================================" &&
            printfn"\npassword is $line\n" &&
            read -p "press return key to continue..." < /dev/tty; 
fi
done < ./password.txt

todavía me muestra salida con el carácter en él

ACTUALIZACIÓN: Resuelto

printf "Working..."

while read line
do
openssl aes-256-cbc -d -a -in $1 -pass pass:$line -out out.txt 2>out.txt >/dev/null
if file out.txt | grep -q 'out.txt: ASCII text'
    then
        printf "\n==================================================\n\n" &&
            cat out.txt &&
            printf "\n==================================================" &&
            printf "\npassword is $line\n" && 
            read -p "press return key to continue..." < /dev/tty;
    else
        : 
fi
done < ./password.txt
Stuart Sloan
fuente
Parece correcto, debería funcionar (por cierto, no tengo ninguna fuente para que vea su carácter Unicode, pero ninguno de ellos tiene un significado especial). grepHace tiempo que entiende unicode (lo que lo hace mucho más lento, por lo que buscar cadenas ASCII LANG=C grepes una gran mejora del rendimiento).
peterh - Restablece a Monica el
Es posible que tenga que eliminar esto y publicar otra pregunta porque estoy seguro de que estoy confundiendo completamente a todos aquí.
Stuart Sloan
@Stuart Sloan, el título de su pregunta es, ¿ How to grep for unicode � in a bash scriptes esto realmente lo que quiere? extraer el unicode? por favor aclarar para que podamos ayudar!
1
@Goro He hecho la edición en mi publicación original. Espero que tenga sentido. Avíseme si no es así e intentaré aclararlo.
Stuart Sloan
1
Ambas respuestas actuales son extremadamente engañosas. Lea (nuevamente) mi respuesta , la he editado para explicar qué está mal con ambas respuestas.
Isaac

Respuestas:

27

grep es la herramienta incorrecta para el trabajo.

Usted ve el U+FFFD REPLACEMENT CHARACTERno porque esté literalmente en el contenido del archivo, sino porque miró un archivo binario con una herramienta que se supone que maneja solo la entrada basada en texto. La forma estándar de manejar entradas no válidas (es decir, datos binarios aleatorios) es reemplazar todo lo que no es válido en la configuración regional actual (probablemente UTF-8) con U + FFFD antes de que llegue a la pantalla.

Eso significa que es muy probable que un literal \xEF\xBF\xBD(la secuencia de bytes UTF-8 para el carácter U + FFFD) nunca ocurra en el archivo. greptiene toda la razón al decirte que no hay ninguno.

Una forma de detectar si un archivo contiene algún binario desconocido es con el file(1)comando:

$ head -c 100 /dev/urandom > rubbish.bin
$ file rubbish.bin
rubbish.bin: data

Para cualquier tipo de archivo desconocido, simplemente dirá data. Tratar

$ file out.txt | grep '^out.txt: data$'

para verificar si el archivo realmente contiene algún binario arbitrario y, por lo tanto, lo más probable es que sea basura.

Si desea asegurarse de que solo se out.txttrata de un archivo de texto codificado UTF-8, también puede utilizar iconv:

$ iconv -f utf-8 -t utf-16 out.txt >/dev/null
Boldewyn
fuente
Tienes toda la razón! desafortunadamente, sigo recibiendo algo (menos que antes) de basura en la salida.
Stuart Sloan
Posiblemente filedetecta algún otro tipo de contenido para esos archivos. Si el 100% siempre sólo se espera UTF-8 archivos de texto codificados, se puede comprobar con iconv, si un archivo es UTF-8 válidos: iconv -f utf-8 -t utf-16 out.txt >/dev/null. Si iconvno puede convertir el archivo debido a secuencias UTF-8 no válidas, volverá con un código de salida distinto de cero.
Boldewyn
2
¡El comando de archivo era correcto! Me ayudaste a resolver mi problema, gracias!
Stuart Sloan
44
Por supuesto que grep "es la herramienta para el trabajo", intente grep -axv '.*' badchars.txt. Eso imprimirá cualquier línea que contenga caracteres Unicode no válidos .
Isaac
1
Esto es extremadamente engañoso, por favor lea en mi respuesta sobre lo que filehace.
Isaac
5

TL; DR:

grep -axv '.*' out.txt 

respuesta larga

Ambas respuestas actuales son extremadamente engañosas y básicamente erróneas.

Para probar, obtenga estos dos archivos (de un desarrollador muy reconocido: Markus Kuhn):

$ wget https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt
$ wget https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt

Manifestación

El primero UTF-8-demo.txtes un archivo diseñado para mostrar qué tan bien UTF-8 puede presentar muchos idiomas, matemáticas, braille y muchos otros tipos de caracteres útiles. Eche un vistazo con un editor de texto (que entienda utf-8) y verá muchos ejemplos y no .

La prueba que propone una respuesta: limitar el rango de caracteres a \x00-\x7Frechazará casi todo dentro de este archivo.
Eso está muy mal y no eliminará ninguno ya que no hay ninguno en ese archivo .

El uso de la prueba recomendada en esa respuesta eliminará 72.5 %el archivo:

$ grep -oP "[^\x00-\x7F]" UTF-8-demo.txt | tr -d '\n' | wc -c
10192
$ cat UTF-8-demo.txt | wc -c
14058

Eso es (para la mayoría de los propósitos prácticos) todo el archivo. Un archivo muy bien diseñado para mostrar caracteres perfectamente válidos.

Prueba

El segundo archivo está diseñado para probar varios casos límite para confirmar que los lectores utf-8 están haciendo un buen trabajo. Contiene muchos caracteres que harán que se muestre una ' '. Pero la otra recomendación de respuesta (la seleccionada) para usar filefalla gravemente con este archivo. Solo eliminar un byte cero ( \0) (que técnicamente es ASCII válido) y un \x7fbyte (DEL - eliminar) (que también es claramente un carácter ASCII) hará que todo el archivo sea válido para el filecomando:

$ cat UTF-8-test.txt | tr -d '\0\177' > a.txt
$ file a.txt 
a.txt: Non-ISO extended-ASCII text, with LF, NEL line terminators

No solo no filepuede detectar los muchos caracteres incorrectos, sino que tampoco puede detectar e informar que se trata de un archivo codificado UTF-8.

Y sí, filees capaz de detectar e informar texto codificado en UTF-8:

$ echo "ééakjfhhjhfakjfhfhaéá" | file -
/dev/stdin: UTF-8 Unicode text

Además, fileno informa como ASCII la mayoría de los caracteres de control en el rango de 1 a 31. ( file) informa algunos rangos como data:

$ printf '%b' "$(printf '\\U%x' {1..6})" | file -
/dev/stdin: data

Otros como ASCII text:

$ printf '%b' "$(printf '\\U%x' 7 {9..12})" | file -
/dev/stdin: ASCII text

Como el rango de caracteres imprimibles (con nuevas líneas):

$ printf '%b' "$(printf '\\U%x' {32..126} 10)" | file -
/dev/stdin: ASCII text

Pero algunos rangos pueden causar resultados extraños:

$ printf '%b' "$(printf '\\U%x' {14..26})" | file -
/dev/stdin: Atari MSA archive data, 4113 sectors per track, starting track: 5141, ending track: 5655

El programa fileno es una herramienta para detectar texto, sino para detectar números mágicos en programas o archivos ejecutables.

Los rangos filedetectados, y el tipo correspondiente informado que encontré fueron:

  • Valores de un byte, principalmente ascii:

    {1..6} {14..26} {28..31} 127   :data
    {128..132} {134..159}          :Non-ISO extended-ASCII text
    133                            :ASCII text, with LF, NEL line terminators
    27                             :ASCII text, with escape sequences
    13                             :ASCII text, with CR, LF line terminators
    8                              :ASCII text, with overstriking
    7 {9..12} {32..126}            :ASCII text
    {160..255}                     :ISO-8859 text
    
  • Rangos codificados Utf-8:

    {1..6} {14..26} {28..31} 127   :data
    27                             :ASCII text, with escape sequences
    13                             :ASCII text, with CR, LF line terminators
    8                              :ASCII text, with overstriking
    7 {9..12} {32..126}            :ASCII text
    {128..132} {134..159}          :UTF-8 Unicode text
    133                            :UTF-8 Unicode text, with LF, NEL line terminators
    {160..255}                     :UTF-8 Unicode text
    {256..5120}                    :UTF-8 Unicode text
    

Una posible solución se encuentra a continuación.


Respuesta previa

El valor Unicode para el personaje que está publicando es:

$ printf '%x\n' "'�"
fffd

Sí, ese es un 'CARÁCTER DE REEMPLAZO' de caracteres Unicode (U + FFFD) . Ese es un carácter utilizado para reemplazar cualquier carácter Unicode no válido encontrado en el texto. Es una "ayuda visual", no un personaje real. Para buscar y enumerar todas las líneas completas que contienen caracteres UNICODE no válidos , use:

grep -axv '.*' out.txt 

pero si solo desea detectar si algún carácter no es válido, use:

grep -qaxv '.*' out.txt; echo $?

Si el resultado es que 1el archivo está limpio, de lo contrario será cero 0.


Si lo que preguntabas era: cómo encontrar el personaje, entonces usa esto:

➤ a='Basically, if the file "out.txt" contains "�" anywhere in the file I'
➤ echo "$a" | grep -oP $(printf %b \\Ufffd)
�

O si su sistema procesa correctamente el texto UTF-8, simplemente:

➤ echo "$a" | grep -oP '�'
�
Isaac
fuente
OMG muchas gracias por grep -axv '.*' !! ¡¡¡He luchado con algunos caracteres malos en mis archivos de texto, y cómo solucionarlos en emacs, ¡por una o dos décadas!
nealmcb
3

Esta respuesta muy temprana fue para la publicación original que era:

Cómo grep para unicode en un script bash

if grep -q "�" out.txt
    then
        echo "working"
    else
        cat out.txt  fi

Básicamente, si el archivo "out.txt" contiene " " en cualquier parte del archivo, me gustaría que haga eco de "trabajo" Y si el archivo "out.txt" NO contiene " " en ningún lugar del archivo, me gustaría a cat out.txt

Tratar

grep -oP "[^\x00-\x7F]"

con una if .. thendeclaración de la siguiente manera:

if grep -oP "[^\x00-\x7F]" file.txt; then
    echo "grep found something ..."
else
    echo "Nothing found!"
fi

Explicación💡:

  • -P, --perl-regexp: PATTERN es una expresión regular de Perl
  • -o, --only-matching: muestra solo la parte de una línea que coincide con PATTERN
  • [^\x00-\x7F] es una expresión regular para que coincida con un solo carácter no ASCII.
  • [[:ascii:]] - coincide con un solo carácter ASCII
  • [^[:ascii:]] - coincide con un solo carácter no ASCII

en bash

LC_COLLATE=C grep -o '[^ -~]' file
Toby Speight
fuente
3
Esto se romperá (tendrá un falso positivo) tan pronto como alguien no hable inglés ...
Kevin
o si alguien intenta discutir a la carta, emoji, Pokémon o cualquier otra cosa que no esté estrictamente limitada a ASCII de 7 bits. Mejor busque cualquier cosa en 00-1F, excepto 09 0A 0D (tabulación, salto de línea, retorno de carro).
Alcaro el
Esta es una muy mala idea. Esto rechazará cualquier carácter Unicode válido por encima del rango ASCII, solo un poco más de un millón de caracteres válidos. Increíble. Prueba: printf '%b' "$(printf '\\U%x' {128..131})" | grep -oP "[^\x00-\x7F]"solo 4 caracteres Unicode válidos que tu código rechaza. :-(
Isaac
Esta es una respuesta extremadamente engañosa. Lea en mi respuesta por qué el enfoque simplista de limitar solo a ASCII falla gravemente.
Isaac