2017-08-14 6 views
0

J'ai un besoin très spécifique, pour lequel j'ai essayé de résoudre, sans succès.Supprimer un caractère non-ascii, seulement si une condition s'applique, dans bash

J'ai un journal, qui est créé par un vidage d'une socket tcp/ip ... Il convertit le Hex en ASCII, mais naturellement il y a des caractères spéciaux dedans.

J'ai réussi à les supprimer, mais je rencontre actuellement une difficulté: Parfois, un 0x0A est envoyé, ce qui désordre avec mes applications ... J'essaie de l'enlever, mais il supprime également le 0x0A valide à la fin de la ligne ...

en fait, je l'ai, dans le fichier journal:

08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={ 
Teste String2} 
08-14-2017 10:00:00 String={ 
Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

Je veux que le résultat final comme

08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={Teste String2} 
08-14-2017 10:00:00 String={Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

les personnages sont toujours entre {}, donc chaque 0x0A après le} est valide, mais à l'intérieur ne l'est pas.

chaque commande que j'ai essayé supprime tous les 0x0A, ou tout simplement ne fonctionne pas du tout.

J'ai essayé des choses comme

sed 's/^[^}]*}//' 
sed 's/\x0A$//' 

toute pensée?

+0

Appliquez-vous la commande sed sur le texte ASCII ou sur l'hexagone? – pchaigno

+0

Sur le texte ASCII ... –

Répondre

1

Ceci est certainement possible avec sed, mais il est plus facile à lire et à comprendre awk:

awk 'BEGIN{ OFS=FS="{"; ORS=RS="}" } { sub(/[^[:print:]]/,"",$2) } 1' input.txt 

Qu'est-ce que cela fait?

  • D'abord, nous avons mis nos séparateurs d'entrée et de sortie sur le terrain à {, et nos séparateurs d'entrée et d'enregistrement de sortie à }. Cela nous permet de saisir de façon prévisible le texte entre parenthèses en tant que champ spécifique (au moins en fonction de vos données d'exemple).
  • Ensuite, nous remplaçons tous les caractères non imprimables dans le champ # 2 par une chaîne vide, en éliminant les retours à la ligne, les retours arrière, etc.
  • Enfin, nous imprimons la ligne en utilisant awk stencil.
0

Avec sed:

Linux:

$ sed -r ':a;N;$!ba;s/(\{[^}]*)\\n([^{]*\})/\1\2/g' file 
08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={Teste String2} 
08-14-2017 10:00:00 String={Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

FreeBSD et Mac OS:

sed -e ':a' -e 'N;$!ba' -e 's/(\{[^}]*)\\n([^{]*\})/\1\2/g' file 

Explications

-e ':a' -e 'N;$!ba' permet de prendre en compte à la fois la ligne courante et la ligne suivante à chaque itération de sed. Voir this SO answer pour plus de détails.

(\{[^}]*) garantit qu'il y a une entretoise d'ouverture non suivie d'une entretoise de fermeture.

([^{]*\}) fait le contraire.

+0

Ne fonctionne pas pour moi sous FreeBSD ou macOS. Est-ce spécifique à GNU-sed? – ghoti

+0

Oui, je vais mettre à jour. – pchaigno

+0

Fonctionne quand vous le divisez: 'sed -E -e ': un' -e 'N; $! Ba' -e 's/(\ {[^}] *) \ n ([^ {] * \ })/\ 1 \ 2/g'' .. non-GNU sed semble vouloir que les étiquettes ne soient pas suivies de points-virgules. – ghoti

0

Perl:

$ perl -0777 -pe 's/({[^}]*)\x0A([^}]*})/\1\2/g' file 
08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={Teste String2} 
08-14-2017 10:00:00 String={Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

Bash pur (basé sur awk de anubhava):

while IFS="\n" read -r line; do 
    le="" 
    [[ $line =~ \} ]] && le=$'\n' 
    printf "%s%s" "$line" "$le" 
done <file 
3

Une autre plus simpleawk:

awk '{printf "%s%s", $0, (/}/ ? ORS : "")}' file 

08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={Teste String2} 
08-14-2017 10:00:00 String={Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

Cette présence vérifie de commande awk de } dans une ligne, puis imprime uniquement un saut de ligne, sinon il imprime l'enregistrement sans saut de ligne.

+1

C'est génial. – dawg

+1

Oui, ça aurait dû être "ORS" :) – anubhava

1

Avec awk GNU RS multi-ombles nous pouvons simplement isoler chaque chaîne {...} et de supprimer des sauts de ligne en son sein:

$ awk -v RS='{[^}]+}' '{ORS=gensub(/\n/,"","g",RT)}1' file 
08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={Teste String2} 
08-14-2017 10:00:00 String={Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

Pour ce cas précis les autres réponses awk fonctionnera très bien, ce qui précède est juste un solution plus générale au problème de l'isolement d'une chaîne délimitée pour ensuite effectuer des opérations sur elle comme la suppression des caractères comme dans ce cas.