Résolu Extraction de lignes particulières d'un fichier

JPetrucci

Habitué
Bonjour,

j'ai un fichier (.log) dans lequel en gros j'ai des patterns de données par exemple de 4 lignes :
1.blablabla texte
2.données 1
3.données 2
4.ligne vide
5.blablabla texte
6.données 1
7.données 2
8.ligne vide
9.etc...


bref j'ai des tas de ligne et ce que je voudrais c'est extraire par exemple une ligne sur 4 à partir de la 2e ligne pour placer toutes les données 1 (ou données2, et même le texte) du pattern dans un fichier txt par exemple.
(En fait même l'idéal, plutôt que de faire 3 scripts pour récupérer les 3 lignes à chaque fois dans 3 fichiers différents puis de les concaténer avec paste ensuite, ce serait de faire ça en une fois dans mon script)

Et là je bloque, j'ai regardé sur le net sur d'autres forums pour tenter de m'inspirer d'utilisation de fonctions genre awk ou grep mais je n'arrive pas à les utiliser de façon à faire ce que je souhaite faire.
Voici un extrait de mon script (mais qui en plus n'est pas reconnu, quand je le lance ça me fait une erreur "command not found") :

testscript
[cpp]#! /bin/bash

for i in 'seq 1 194' ;
x=4*i - 1

do
awk 'NR==x' fichier.log > données1.txt
done[/cpp]

ou aussi j'ai tenté une une version alternative mais qui ne marche pas non plus :

[cpp]awk ' BEGIN
{
for (i=1;i<=194;i++)
{
x=i*4 - 1
print $x
}
}
END ' /home/chemin/fichier.log > données1.txt
[/cpp]

je précise que quand je le lance je suis dans le répertoire où il est, que je l'ai rendu exécutable en faisant "chmod a+x testscript".
Le 194 c'est parce que y'a 194 patterns de 4 lignes, donc j'ai voulu boucler ça mais je suis pas sûr de m'y être bien pris.

Mon fichier log si ça peut vous aider ressemble à ça :

[cpp]
Apr 15 11:49 [nomdufichiertraité1.fits[*,1]]:
1974.419 1.117 -1.26 1.126 -1.62 73.02 0.
( 764.87) ( ) (9.4) ( 8.427) (2.7) ( 395.4) ( 0.)

Apr 15 11:49 [nomdufichiertraité2.fits[*,1]]:
1984.702 1.265 -8.55 0.676 -9.72 8.268 0.
( 1.6385) ( ) (3.2) ( 0.2504) (3.6) ( 4.219) ( 0.)

etc...
[/cpp]

Ce que je voudrais faire pour résumer donc, c'est créer un fichier de 3 colonnes et 194 lignes contenant :
- en 1ere colonne le nom du fichier traité (donc là je suppose que je dois boucler un cut -c en précisant d'où à où je coupe de sorte à ne pas garder les "[" ainsi que la date et le reste des caractères non désirés, ou alors un grep?)
- en 2e colonne une donnée particulière de la 2e ligne (par exemple la 3e donnée, là aussi je vais de voir utiliser un cut je pense, ou un awk même puisqu'elles sont déjà en colonnes)
- en 3e colonne idem une donnée particulière entre parenthèses de la 3e ligne, par exemple la 3e donnée aussi si je décide de sélectionner la 3e sur la ligne du dessus



Voilà en gros mon problème, dans les scripts que j'ai commencé à faire je me contentais d'abord d'essayer d'extraire une ligne particulière, alors déjà que je n'y suis pas arrivé je n'ai pas encore essayé de faire le reste, mais si vous avez des pistes cela m'aiderait beaucoup !

merci d'avance de votre aide et n'hésitez pas à me redemander des trucs si je n'ai pas été assez clair ou pas assez complet ;)

Julien
 

mykhi

Force Modéra-Bleue
Staff
Sans rentrer dans le détail de ton script pour l'instant, concernant son éxécution tu utilises bien la commande suivante :

./testscript
 

zeb

Modérateur
@JPetrucci : Salut. [strike]Utilise
Code:
 et [fixed], pas [quote] s'il te plaît.[/strike] Merci
[:zeb:3]
 

zeb

Modérateur
Etudie ce petit tout petit script awk :

Code:
BEGIN {I=1}
{print > "fichier_n"I".txt" ; I++ }

A toi maintenant de faire des opérations pour faire évoluer I en fonction de tes besoins.
Propose-nous tes réflexions, on en discutera.
 

JPetrucci

Habitué
merci pour vos réponses !

sinon oui là je me sens bien stupide : l'habitude Matlab d'exécuter les scripts juste en tapant le nom, j'avais bel et bien oublié de taper le ./ avant le nom...
pour les balises "code" j'avais pas vu désolé, je vais y faire attention maintenant !

je vais voir tout ça d'ici demain car là j'ai pas trop le temps et je vous tiens au courant assez rapidement alors ;)



 

mykhi

Force Modéra-Bleue
Staff
De rien !

Pour ton script je laisse la place aux spécialistes. Ca fait longtemps que je n'ai pas mis les doigts dans du shell.
 

JPetrucci

Habitué
@ Zeb : alors j'ai essayé ton petit script awk et là en fait ça me créé juste des fichiers qui sont nommés en fonction de I qui croit jusqu'à ce que j'arrête de faire tourner le script.

J'ai donc remarqué que dans mes scripts il fallait des instructions dans le BEGIN et END, ce que j'avais oublié de faire.

J'ai tenté ça :
[cpp]awk ' BEGIN {I=1}
{
x=(I*4)-1
{ print $x : I++ }
}
END{I<=194} ' /home/chemin/fichier.log > fichier.txt [/cpp]


mais ça me retourne une erreur de syntaxe, je vois pas trop comment arriver à extraire ces lignes, comment gérer la sélection à partir de mon opération basique x=4*I-1 par exemple.
 

JPetrucci

Habitué
alors vite fait j'ai remarqué mon erreur : j'ai mis un ":" par inadvertance au lieu d'un ";"
Le script tourne maintenant mais il me créé juste un fichier comprenant 777 lignes (donc 4*194+1 lignes) qui sont vierges.

il ne va donc pas chercher dans mon fichier.log les lognes voulues pour les imprimer dans le fichier.txt
je vais tenter 2/3 trucs en attendant des pistes, je vous tiens au courant si je trouve la solution en attendant votre aide.

merci d'avance ;)
 

mykhi

Force Modéra-Bleue
Staff
Voici comment j'ouvre un fichier en lecture dans un script :

[cpp]i=0
for BUF in `cat $FICHIER`
do
if [condition] then action fi
i=$i+1
done[/cpp]

Tu accèdes à la ligne courante par $BUF. A toi de faire un test sur le numéro de ligne en cours ($i) et éventuellement de traiter ta ligne avec un cut ou autre pour récupérer ce que tu veux.
 

JPetrucci

Habitué
Merci pour cette piste, j'ai essayé de l'adapter ainsi mais j'ai toujours une erreur :

[cpp]i=1
for BUF in `cat $erreqw1978.log`
x=($i+1)/4
do
if let $x 2>/dev/null then print $BUF > eqw1978.txt fi
i=$i+1
done[/cpp]

l'erreur retournée est : Erreur de syntaxe près du symbole inattendu « x=($i+1)/4 »
j'ai essayé de rajouter un ";" comme sous Matlab mais ça n'a rien changé, une idée sur ce que j'ai raté ?
 

mykhi

Force Modéra-Bleue
Staff
inverse ligne 3 et ligne 4 ... Le do doit forcément se trouver après le for.

Pour être plus propre créé une constante FICHIER (par exemple) et donne lui comme valeur le nom de ton fichier à analyser (et chemin complet si il n'est pas dans le répertoire du script)
 

JPetrucci

Habitué


ok merci, je viens de tenter ça donc :

[cpp]FICHIER='erreqw1978.log'
i=1
x=($i+1)/4
for BUF in `cat $FICHIER`
do
if let $x 2>/dev/null then print $BUF > eqw1978.txt fi
i=$i+1
done[/cpp]

mais ça me renvoie toujours l'erreur, cette fois ci pour le "done" : Erreur de syntaxe près du symbole inattendu « done »

j'ai zappé un signe ?

PS : je viens de capter mais si je vire mon expression de x de la boucle ça va pas marcher ? il faut que je le mette dans la boucle for non si je veux qu'il évolue en fonction de i et pouvoir ainsi sélectionner les lignes ?
 

mykhi

Force Modéra-Bleue
Staff
Si tu fais ce que tu as mis, x va prendre sa valeur une fois ((1+1)/4 en l'occurrence) et ne bougera plus. Je te conseille quelque chose du genre :

[cpp]FICHIER='erreqw1978.log'
i=1
for BUF in `cat $FICHIER`
do
x=($i+1)/4
if let $x 2>/dev/null
then
print $BUF > eqw1978.txt
fi
i=$i+1
done[/cpp]

Tant que tu ne rentres pas dans la structure du if, tu peux effectuer autant de commandes que tu le souhaites.
 

JPetrucci

Habitué
ok merci ! j'avais retenté en mettant l'expression mais après le do mais ça me retournait aussi la même erreur.

j'ai testé ce que tu m'as dit, ça a l'air de bien parcourir mon fichier mais ça fait des erreurs, voici un extrait de ce que ça me retourne :

[cpp]
....
Error: no such file "11:51"
Warning: unknown mime-type for "[sc_F02D002_910276278_atm_clean_dopcor.fits[*,1]]:" -- using "application/octet-stream"
Error: no such file "[sc_F02D002_910276278_atm_clean_dopcor.fits[*,1]]:"
Error: no such file "1976.975"
Error: no such file "4.219E-18"
Error: no such file "-9.05E-19"
Error: no such file "0.2145"
Error: no such file "-4.24E-19"
Error: no such file "2.005"
Warning: unknown mime-type for "0." -- using "application/octet-stream"
Error: no such file "0."
Warning: unknown mime-type for "(" -- using "application/octet-stream"
Error: no such file "("
Error: no such file "1.2548)"
Warning: unknown mime-type for "(" -- using "application/octet-stream"
Error: no such file "("
Warning: unknown mime-type for ")" -- using "application/octet-stream"
Error: no such file ")"
Error: no such file "(1.1E-18)"
Warning: unknown mime-type for "(" -- using "application/octet-stream"
Error: no such file "("
....
[/cpp]

apparemment si je comprends bien ça considère mes données comme des fichiers ?
merci de ton aide jusqu'à présent en tout cas ;)
 

mykhi

Force Modéra-Bleue
Staff
Meilleure réponse
Bon désolé mon script initial n'était pas une bonne piste. Celà ne traite pas les lignes mais tout ce qui est séparé par un espace.

Voici un code awk pour n'afficher qu'une ligne sur 4 de ton fichier de log :

[cpp]FICHIER=erreqw1978.log
awk 'NR%4==0{print $0}' $FICHIER[/cpp]
 

zeb

Modérateur
Rhooooolala.

Bon, d'abord, savoir si on veut une soluce en awk ou en shell.

Ensuite, si en awk on fait des trucs à la fin (END), on ne le fait qu'une fois, à la fin [:spamafote]
Re-étude :
Code:
BEGIN {I=1; J=0}
{print > "fichier_n"I".txt" ; J++ ; if (J%4==0) I++ }

Code:
for BUF in `cat $FICHIER`
Que c'est pas beau !
En Bourne shell (bsh), c'est Ok. Mais depuis, il y a eu le Korn (ksh) puis le Bourne Again (bash). Alors on n'utilise plus la syntaxe anti-quotes `commande` mais la syntaxe dollar-parenthèses $( commande ). Le gros intérêt, en plus de vivre avec son temps, c'est que la syntaxe dollar-parenthèses est imbricable.

Code:
for BUF in $( cat $FICHIER )
Si le fichier contient des lignes avec espaces, ça ne marche plus. Voici une astuce pour prendre toute la ligne :
Code:
cat $FILE |
while read LINE ; do
  echo "$LINE
done

JP, respecte la syntaxe des commandes. Quand mykhi passe une ligne, fais-en autant, ou utilise un point-virgule :
Code:
# // bon
if ..
then
  ...
fi

while ..
do
	...
done

# // pas bon
if .. then
 ...
fi

while .. do
	...
done

# // bon
if .. ; then ... ; fi
while .. ; do ... ; done
 

zeb

Modérateur
Ah, mykhi s'est repris :o A la base c'est une bonne idée quand même ;)
La soluce, c'est le cat .. | while read ..
 

mykhi

Force Modéra-Bleue
Staff


tu devais être en train de rédiger ton message quand j'ai posté le mien.
 

mykhi

Force Modéra-Bleue
Staff
Oui mais bon ton message valait la peine d'attendre. Je ne suis qu'un amateur en shell. Je me débrouille pour mes besoins mais ce n'est certainement pas ce qui se fait de mieux en général.
 
Vous devez vous inscrire ou vous connecter pour répondre ici.
Derniers messages publiés
Statistiques globales
Discussions
730 131
Messages
6 717 954
Membres
1 586 382
Dernier membre
alejandrooo
Partager cette page
Haut