1

Soit un fichier plat classique avec des colonnes de longueur variable, séparées par des |
Chaque ligne commence par la séquence ZZZ

Exemple:
ZZZ|xxx|xxxxx|x|||x||x|||
ZZZ|xxx|xxxxx|x|||x||x|||x

Il arrive que dans certains champs, un retour chariot se glisse, ce qui donne:
ZZZ|xxx|xx
xxx|x|||x||x|||
ZZZ|xxx|xxxxx|x|||x||x|||x

Du coup le chargement de ce fichier via un bête sqlldr dans une base oracle pose problème.

Je cherche à "corriger" ce fichier avant intégration par un bête fichier.

Ce que je peux faire facilement avec un grep et un grep -v , c'est de créer un fichier avec les lignes correctes et un autre avec celles qui vont poser problème.

Mais j'aimerai aller plus loin et pourquoi pas carrément supprimer les retours chariot en trop avant intégration.

Seulement mes connaissances en bash ou autre awk et sed sont très limités.

Pensez-vous que c'est jouable ? des pistes ?

Merci smile

2

c'est chiant, faut trouvirer tous les retours chariots non suivis de ZZZ.

sed /\n([^Z]{3})/\1/g ?

ça doit avoir ce gout là.

3

autre solution beaucoup plus tordue, je garantis pas que ça marche grin

sed -nr '/^ZZZ(.*)$/ { x;/.+/p } ; /^ZZZ(.*)$/ !{ H;x;s/^(.*)\n(.*)$/\1\2/;x } ; $ { x;p }' <ton fichier>

(ça permet de parcourir le fichier, de concaténer chaque ligne à la précédente quand elle ne commence pas par ZZZ, et d'afficher le résultat de cette concaténation quand on tombe sur une "vraie" nouvelle ligne qui commence par ZZZ)
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

4

t1 comment vous faites pour coder dans des langages aussi imbitables sick

5

6

J'ai travaillé un peu sur la version de squalyl, mais le sed avec détection de \n n'est pas possible.
( http://forum.macbidouille.com/index.php?showtopic=128499 )

Du coup, faut que je décode le truc de bob, qui ne tourne pas tel quel tongue
De toute manière faut que je comprenne comment ça marche avant de pouvoir m'en servir.

Merci à vous deux en tout cas !

7

Folco (./4) :
t1 comment vous faites pour coder dans des langages aussi imbitables sick


+1

8

iwannabeamaki (./3) :
autre solution beaucoup plus tordue, je garantis pas que ça marche grin

sed -nr '/^ZZZ(.*)$/ { x;/.+/p } ; /^ZZZ(.*)$/ !{ H;x;s/^(.*)\n(.*)$/\1\2/;x } ; $ { x;p }' <ton fichier>

(ça permet de parcourir le fichier, de concaténer chaque ligne à la précédente quand elle ne commence pas par ZZZ, et d'afficher le résultat de cette concaténation quand on tombe sur une "vraie" nouvelle ligne qui commence par ZZZ)


le -r ne semble pas être une option valable :/

sed: illegal option 'r'

9

10

Ah merde, t'as quelle version ? J'ai jamais vu un sed où l'option -r ne soit pas disponible ; regarde dans le man si elle n'a pas un autre switch par hasard : c'est l'option qui permet d'utiliser des "extended regular expressions". Si tu ne l'a pas, il faudra échapper tout un tas de caractères spéciaux, comme les parenthèses (mais je ne connais pas la liste exacte et flemme de chercher grin)

Sinon pour expliquer brièvement, la commande se décompose en trois parties qui sont trois traitements à appliquer à chaque ligne :
sed -nr '/^ZZZ(.*)$/ { x;/.+/p } ; /^ZZZ(.*)$/ !{ H;x;s/^(.*)\n(.*)$/\1\2/;x } ; $ { x;p }' <ton fichier>


En rouge, on ne prend la ligne en compte que si elle commence par ZZZ (regexp: ^ZZZ(.*)$). Dans ce cas, on est sur le début d'une ligne, donc on va afficher celle qu'on avait gardé en mémoire jusqu'ici ("x" permet d'alterner entre la ligne active et le buffer interne, "p" permet d'afficher).

En vert, on ne prend la ligne en compte que si elle ne commence pas par ZZZ. Dans ce cas, on est sur la suite d'une ligne précédente qu'on a déjà dans notre buffer interne. On va la concaténer au buffer (commande "H"), qui contient donc les deux lignes séparées par "\n", puis effectuer une substitution pour dégager ce "\n" (commande "s/^(.*)\n(.*)$/\1\2/").

En bleu, on effectue un traitement une fois la fin du fichier atteinte, pour afficher le contenu de ce qu'il reste dans le buffer (sinon la dernière ligne du fichier va rester dans le buffer et ne sera jamais affichée, puisqu'elle n'est pas suivie par une ligne en "ZZZ").

Chez moi ça marche ©, mais peut-être que tu devras faire quelques ajustements selon ton besoin smile
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

11

12

C'est la version de SED embarqué dans les sfu, elle doit dater ...

pas de trace d'extended regexp :/

du coup j'essaye de décomposer ton code étape par étape pour le comprendre en antislasher ce qu'il faut.

{ x;/.+/p }'Je passe un sed -n '/^ZZZ(.*)$/

et j'ai l'erreur suivante:

sed: 1: "/^EMP(.*)$/{x;\/.+/p}": extra characters at the end of p command

Même en escapant les () ça ne change rien

13

tiens faut que je rajoute des retour chariot dans l'expression happy

14

Pourquoi l'erreur ne correspond pas à la commande que tu as passée ? grin

Sinon oui c'est possible qu'il faille arranger l'expression (à coups de retour à la ligne, d'ajout ou de suppression de blancs, ou de \) pour que ton sed l'accepte, je ne connais pas du tout les anciennes versions :/
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

15

et sinon, ce genre d'incantation marche aussi quand les fins de lignes sont \r\n ? grin

16

Ahah, malheureux, non bien sûr grin

En fait si, mais je pense que ça va laisser trainer des "\r" dans le buffer, il faudrait les stripper en remplaçant "(.*)\n(.*)" par "(.*)\r?\n(.*)", ou un truc du genre smile
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

17

la j'ai une commande qu'il accepte, mais ça fait des résultats bizarres sur mon fichier.
ça corrige bien le retour chariot dans un cas, mais je perds plein de ligne dans le traitement.

18

oui ça fait un caractère bizarre le \r\n puisqu'il reste le \r effectivement.

sinon j'en suis à ça niveau commande:
sed -n '/^ZZZ\(.*\)$/ {
	x;
	/.+/p
	};
	/^ZZZ\(.*\)$/ !{
	H;
	x;
	s/^\(.*\)\n\(.*\)$/\1\2/;
	x
	} ; 
	$ {
	x;
	p
	}'

19

Pour le(s) fan(s): mon fichier de test

ZZZ|toto1
ZZZ|toto2
ZZZ|to
to3
ZZZ|pwic1
ZZZ|pwic2
ZZZ|pwic3
ZZZ|pwic4
ZZZ|pwic5
ZZZ|pwic6
ZZZ|pwic7
ZZZ|pwic8
ZZZ|pwic9
ZZZ|pwic10
ZZZ|pwic11
ZZZ|pwic12
ZZZ|pwic13
ZZZ|pwic14
ZZZ|pwic15
ZZZ|pwic
16

ZZZ|dada1
ZZZ|dada2
ZZZ|dada3
ZZZ|dada4
ZZZ|dada5


Actuellement, plus rien ne marche grin

20

iwbam: ça m'étonne que personne n'ait inventé un "\eol" pour matcher \r\n ou \n ou \r, y'a pourtant bien \s qui matche tab et espace ^^ (non, $ ne fait pas ça ^^)

21

./20 : tu peux utiliser \s mais ça peut bouffer plus de caractères que ce dont tu as besoin :/

./19 : je viens de tester, il n'y a besoin d'échapper que les parenthèses et le "+" a priori, donc chez moi ça marche avec ça quand on enlève le switch "-r" :

sed -n '/^ZZZ\(.*\)$/ { x;/.\+/p } ; /^ZZZ\(.*\)$/ !{ H;x;s/^\(.*\)\n\(.*\)$/\1\2/;x } ; $ { x;p }' fichier
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

22

et ça marche sur mon fichier test ?
moi ça ne me sort que la dernière ligne :/

il doit y avoir d'autres diffénces entre nos versions

23

Ça me sortait la dernière ligne avant que j'ajoute un \ devant le +, mais maintenant ça marche chez moi oui, faudrait tester section par section pour trouver les différences entre ton sed et le mien :/
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

24

zarb chez moi il ne change rien.

25

Essaie de faire des plus petits tests avec juste une commande genre '/^ZZZ\(.*\)$/ { /.\+/p }' pour essayer de trouver à quel moment les comportements diffèrent ?

Sinon tu as aussi la possibilité de faire ça en shell script, ça ira probablement plus vite que d'essayer de comprendre pourquoi sed marche pas grin
#! /bin/sh buffer='' while read line; do if [ `echo "$line" | grep '^ZZZ'` ]; then if [ "$buffer" ]; then echo "$buffer" fi buffer="$line" else buffer="$buffer$line" fi done < test echo "$buffer"
Mais c'est moins classe sad
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

26

C'est bizarre je mets 10x moins de temps à comprendre ce code, qui semble bien fonctionner grin

27

En fait je suis bête, le sed doit merde parce que ce sont des \r\n de windows

28

Arf c'est une précision qui a son importance, oui grin
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

29

30

le dernier script semble foirer quelques fois, selon le contenu des lignes qui semble être interprété au moment du grep.


unexpected operator/operand