Comment grep pour unicode dans un script bash

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

Fondamentalement, si le fichier "out.txt" contient " " n'importe où dans le fichier, je voudrais qu'il fasse écho à "working" ET si le fichier "out.txt" ne contient PAS " " n'importe où dans le fichier, alors je voudrais à cat out.txt

EDIT: Alors, voici ce que je fais. J'essaie de forcer brutalement un déchiffrement openssl.

openssl enc renvoie 0 en cas de succès, différent de zéro sinon. Remarque: vous obtiendrez des faux positifs car AES / CBC ne peut déterminer que si le "décryptage fonctionne" en fonction du bon remplissage. Donc, le fichier se déchiffre mais ce ne sera pas le bon mot de passe, il y aura donc du charabia. Un caractère commun dans le charabia est " ". Je veux donc que la boucle do continue si la sortie contient " ".

Voici mon lien git https://github.com/Raphaeangelo/OpenSSLCracker Voici le 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

il me montre toujours la sortie avec le charicter dedans

MISE À JOUR: Résolu

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
la source
Il a l'air correct, il devrait fonctionner (btw, je n'ai pas de police pour votre caractère unicode à voir, mais aucun n'a de signification particulière). grepcomprend depuis longtemps unicode (ce qui le rend beaucoup plus lent, donc pour rechercher des chaînes ascii, a LANG=C grepest une énorme amélioration des performances).
peterh
Je devrais peut-être supprimer cela et poster une autre question parce que je suis sûr que je suis complètement déroutant ici.
Stuart Sloan
@Stuart Sloan le titre de votre question est: How to grep for unicode � in a bash scriptest-ce vraiment ce que vous voulez? extraire l'unicode? veuillez clarifier afin que nous puissions vous aider!
1
@Goro J'ai effectué la modification de mon message d'origine. J'espère que ça a du sens. S'il vous plaît laissez-moi savoir si ce n'est pas le cas et je vais essayer de clarifier.
Stuart Sloan
1
Les deux réponses actuelles sont extrêmement trompeuses. Veuillez lire (encore) ma réponse , je l'ai édité pour expliquer ce qui ne va pas avec les deux réponses.
Isaac

Réponses:

27

grep n'est pas le bon outil pour le travail.

Vous voyez le U+FFFD REPLACEMENT CHARACTERnon pas parce qu'il est littéralement dans le contenu du fichier, mais parce que vous avez regardé un fichier binaire avec un outil qui est censé gérer uniquement les entrées textuelles. La manière standard de gérer les entrées non valides (c'est-à-dire les données binaires aléatoires) consiste à remplacer tout ce qui n'est pas valide dans les paramètres régionaux actuels (probablement UTF-8) par U + FFFD avant qu'il n'apparaisse à l'écran.

Cela signifie qu'il est très probable qu'un littéral \xEF\xBF\xBD(la séquence d'octets UTF-8 pour le caractère U + FFFD) ne se produise jamais dans le fichier. grepa tout à fait raison de vous le dire, il n'y en a pas.

Une façon de détecter si un fichier contient un binaire inconnu est avec la file(1)commande:

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

Pour tout type de fichier inconnu, il dira simplement data. Essayer

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

pour vérifier si le fichier contient vraiment des fichiers binaires arbitraires et donc très probablement.

Si vous voulez vous assurer qu'il out.txts'agit bien d'un fichier texte encodé en UTF-8, vous pouvez également utiliser iconv:

$ iconv -f utf-8 -t utf-16 out.txt >/dev/null
Boldewyn
la source
Tu as parfaitement raison! malheureusement, je reçois toujours (moins qu'avant) des déchets dans la sortie.
Stuart Sloan
Détecte éventuellement fileun autre type de contenu pour ces fichiers. Si vous 100% toujours seulement attendre UTF-8 fichiers texte codé, vous pouvez vérifier avec iconv, si un fichier est UTF-8 valide: iconv -f utf-8 -t utf-16 out.txt >/dev/null. Si iconvne peut pas convertir le fichier en raison de séquences UTF-8 invalides, il reviendra avec un code de sortie non nul.
Boldewyn
2
La commande file avait raison! Vous m'avez aidé à résoudre mon problème merci!
Stuart Sloan
4
Bien sûr, grep "est l'outil pour le travail", essayez grep -axv '.*' badchars.txt. Cela imprimera toute ligne contenant un caractère Unicode non valide .
Isaac
1
C'est extrêmement trompeur, veuillez lire ma réponse sur ce qui se filepasse.
Isaac
5

TL; DR:

grep -axv '.*' out.txt 

longue réponse

Les deux réponses actuelles sont extrêmement trompeuses et fondamentalement erronées.

Pour tester, obtenez ces deux fichiers (d'un développeur très réputé: 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

Démo

Le premier UTF-8-demo.txtest un fichier conçu pour montrer à quel point UTF-8 est capable de présenter de nombreuses langues, mathématiques, braille et de nombreux autres types de caractères utiles. Jetez un oeil avec un éditeur de texte (qui comprend utf-8) et vous verrez beaucoup d'exemples et non .

Le test que propose une réponse: limiter la plage de caractères à \x00-\x7Frejettera presque tout ce qui se trouve dans ce fichier.
C'est très faux et n'en supprimera aucun car il n'y en a pas dans ce fichier .

L'utilisation du test recommandé dans cette réponse supprimera 72.5 %le fichier:

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

Il s'agit (à des fins plus pratiques) de l'ensemble du dossier. Un fichier très bien conçu pour montrer des caractères parfaitement valides.

Tester

Le deuxième fichier est conçu pour essayer plusieurs cas de frontière afin de confirmer que les lecteurs utf-8 font du bon travail. Il contient à l'intérieur de nombreux caractères qui feront apparaître un ' '. Mais l'autre recommandation de réponse (celle sélectionnée) à utiliser fileéchoue grossièrement avec ce fichier. Seule la suppression d'un octet zéro ( \0) (qui est techniquement valide ASCII) et d'un \x7foctet (DEL - supprimer) (qui est clairement un caractère ASCII également) rendra tout le fichier valide pour la filecommande:

$ 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

Non seulement ne parvient filepas à détecter les nombreux caractères incorrects, mais également à détecter et à signaler qu'il s'agit d'un fichier codé UTF-8.

Et oui, fileest capable de détecter et de signaler du texte encodé en UTF-8:

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

Également, filene signale pas en ASCII la plupart des caractères de contrôle compris entre 1 et 31. Il ( file) signale certaines plages comme data:

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

D'autres comme ASCII text:

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

En tant que plage de caractères imprimables (avec sauts de ligne):

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

Mais certaines plages peuvent provoquer des résultats étranges:

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

Le programme filen'est pas un outil pour détecter du texte, mais pour détecter des nombres magiques dans des programmes ou fichiers exécutables.

Les plages filedétectent et le type correspondant signalé que j'ai trouvé était:

  • Valeurs d'un octet, principalement 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
    
  • Plages codées 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
    

Une solution possible se trouve ci-dessous.


Réponse précédente.

La valeur Unicode du personnage que vous publiez est:

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

Oui, c'est un caractère Unicode 'CHARGEUR DE REMPLACEMENT' (U + FFFD) . Il s'agit d'un caractère utilisé pour remplacer tout caractère Unicode non valide trouvé dans le texte. C'est une "aide visuelle", pas un vrai personnage. Pour rechercher et répertorier chaque ligne complète contenant des caractères UNICODE non valides, utilisez:

grep -axv '.*' out.txt 

mais si vous voulez seulement détecter si un caractère n'est pas valide, utilisez:

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

Si le résultat est que 1le fichier est propre, sinon il sera nul 0.


Si ce que vous demandiez était: comment trouver le personnage, alors utilisez ceci:

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

Ou si votre système traite correctement le texte UTF-8, simplement:

➤ echo "$a" | grep -oP '�'
�
Isaac
la source
Merci beaucoup OMG pour grep -axv '.*' !! J'ai eu du mal avec quelques mauvais caractères dans mes fichiers texte, et comment les corriger dans emacs, pendant une décennie ou deux !!!
nealmcb
3

Cette réponse très précoce était pour le poste d'origine qui était:

Comment grep pour unicode dans un script bash

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

Fondamentalement, si le fichier "out.txt" contient " " n'importe où dans le fichier, je voudrais qu'il fasse écho à "working" ET si le fichier "out.txt" ne contient PAS " " n'importe où dans le fichier, alors je voudrais à cat out.txt

Essayer

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

avec une if .. thendéclaration comme suit:

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

Explication💡:

  • -P, --perl-regexp: PATTERN est une expression régulière Perl
  • -o, --only-matching: affiche uniquement la partie d'une ligne correspondant au MOTIF
  • [^\x00-\x7F] est une expression régulière pour correspondre à un seul caractère non ASCII.
  • [[:ascii:]] - correspond à un seul caractère ASCII
  • [^[:ascii:]] - correspond à un seul caractère non ASCII

dans bash

LC_COLLATE=C grep -o '[^ -~]' file
Toby Speight
la source
3
Cela se cassera (aura un faux positif) dès que quelqu'un ne parlera pas anglais ...
Kevin
ou si quelqu'un essaie de discuter à la carte, d'emoji, de Pokémon ou de toute autre chose non strictement limitée à l'ASCII 7 bits. Mieux vaut chercher quoi que ce soit en 00-1F, sauf 09 0A 0D (tabulation, saut de ligne, retour chariot).
Alcaro
C'est une très mauvaise idée. Cela rejettera tout caractère Unicode valide au-dessus de la plage ASCII, juste un peu plus d'un million de caractères valides. Incroyable. Essayez: printf '%b' "$(printf '\\U%x' {128..131})" | grep -oP "[^\x00-\x7F]"seulement 4 caractères Unicode valides que votre code rejette. :-(
Isaac
C'est une réponse extrêmement trompeuse. Veuillez lire dans ma réponse pourquoi l'approche simpliste de limiter uniquement à ASCII échoue grossièrement.
Isaac