Rapatrier les deux dernières lignes à côté de

Résolu/Fermé
Swiss Knight - 6 juin 2012 à 17:08
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 - 7 juin 2012 à 23:22
Bonjour tout le monde.

j'ai un fichier texte avec ça dedans :
lambda value idx1 idx2 caract
290 0.888
380 0.518
385 0.454
445 0.139
6.53 2.54
1.12

ce sont des mesures de spectrométrie. bref.
Le truc, c'est que le ligne 1 peut être différente d'un fichier à l'autre en ce sens où elle peut avoir plus ou moins d'indices "idxn". (ici il y en a deux : "idx1" et "idx2")
Les lignes 2 à 5 dans cet exemple, contiennent des valeurs remarquables, et là il peut y avoir plusieurs lignes. Il y en a 4 ici, mais c'est un nombre variable d'un fichier à l'autre.
L'avant dernière ligne contient les indices, à savoir les valeurs de "idx1" et de "idx2" ici.
S'il y avait N indices décrits dans la 1ère lignes, il y aurait N valeurs différentes sur cette avant-dernière ligne.
Et la dernière ligne contient la valeur "caract".

j'aimerai rapatrier les valeurs des indices sous leurs noms respectifs et cette dernière ligne sous le nom "caract" pour obtenir ceci :
lambda value idx1 idx2 caract
290 0.888 6.53 2.54 1.12
380 0.518
385 0.454
445 0.139

je m'embrouille les pinceaux avec awk et les $NF $NR-1 et compagnie (il y a peut-être un moyen plus facile qu'awk aussi) :-/
Si quelqu'un a une idée facile à mettre en place, je suis preneur avec tous mes remerciements.

ps : je travaille sur ubuntu 10.04. Et la version d'awk présente sur le système est la 3.1.6.
La version de sed est là 4.2.1 si ça peut aider.
A voir également:

6 réponses

zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 407
6 juin 2012 à 17:54
Salut,

Tiens une façon de faire avec "ed" (l'ancêtre de "sed") :

$ cat plop
lambda value idx1 idx2 caract
290 0.888
380 0.518
385 0.454
445 0.139
6.53 2.54
1.12

$ ed -s plop <<<$'$-1s/^/ /\n$s/^/ /\n$-1,$j\n$m2\n2,3j\n,p'
lambda value idx1 idx2 caract
290 0.888 6.53 2.54 1.12
380 0.518
385 0.454
445 0.139

$

Pour que les changements soit pris en compte, soit tu rediriges le tout dans un fichier, soit tu change le ",p" (virgule comprise) final de la commande par un "w"
;-))
2
dubcek Messages postés 18718 Date d'inscription lundi 15 janvier 2007 Statut Contributeur Dernière intervention 22 mars 2024 5 615
7 juin 2012 à 08:13
hello
avec awk
 $ awk '{x[NR]=$0}END{print x[1] ; print x[2], x[NR-1], x[NR] ; for (n=3;n<NR-1;)print x[n++]}' fichier
lambda value idx1 idx2 caract
290 0.888 6.53 2.54 1.12
380 0.518
385 0.454
445 0.139
$ 
2
dubcek Messages postés 18718 Date d'inscription lundi 15 janvier 2007 Statut Contributeur Dernière intervention 22 mars 2024 5 615
Modifié par dubcek le 7/06/2012 à 16:12
code awk qui traite tous les fichiers en 1 fois, les nouveaux fichiers ont un .2 ajouté, modifiable bien sûr
$ awk 'BEGIN{for (n=1;n<ARGC;n++){f=ARGV[n]; i=0;while("cat " f | getline)x[++i]=$0 ; print x[1] "\n" x[2], x[i-1], x[i] > f ".2" ; for (m=3;m<i-1;)print x[m++]> f ".2"}}'  fichier* 
$  
1
Swiss Knight Messages postés 1956 Date d'inscription samedi 22 novembre 2008 Statut Membre Dernière intervention 27 juillet 2016 110
7 juin 2012 à 22:57
ça ça me parraît être la meilleure solution "dans mon cas", je ne dis bien sûr pas que les autres sont mauvaises, juste plus difficiles à mettre en place, celle-ci elle est passée comme une lettre à la poste, merci beaucoup ! ;)
0
okay, merci pour ta réponse, alors, en faisait ceci :

$ ed -s iIndices_sample_tmpET1.txt <<<$'$-1s/^/ /\n$s/^/ /\n$-1,$j\n$m2\n2,3j\n,p' > out.txt

ça a l'air de tout bien fonctionner, même si le nombre des indices varie ou que les premières lignes, dès la 2ème, ne sont pas toujours présentent en même quantité.

merci beaucoup, j'espère savoir faire ça tout seul un jour :s
0
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 407
6 juin 2012 à 18:41
même si le nombre des indices varie
Oui, peu importe.


ou que les premières lignes, dès la 2ème, ne sont pas toujours présentent en même quantité.
Tu entends quoi par là exactement ??? Si c'est les lignes après la 2nde et avant l'avant-dernière, oui, on s'en fiche aussi, peu importe leur nombre.

La condition c'est que la 1ère et 2ème ligne soient immuables ainsi que la dernière et l'avant-dernière, non ?
0
Swiss Knight
6 juin 2012 à 18:43
Oui c'est tout comme t'as dit là, du moins je m'arrange pour que les fichiers remplissent ces conditions au minimum ! Et tout devrait fonctionner.

encore juste une petite question : il y a moyen de faire en sorte que tous les fichiers texte présents dans un dossier subissent ce même traitement ?
0
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 407
6 juin 2012 à 18:48
Ave "ed" non malheureusement ;-(

Il te suffit de faire une boucle en bash.
0
Swiss Knight Messages postés 1956 Date d'inscription samedi 22 novembre 2008 Statut Membre Dernière intervention 27 juillet 2016 110
6 juin 2012 à 21:47
Arf mince, le problème est que je lance cette commande depuis un autre soft, ça risque d'être vite trop tordu pour faire le script bash et j'ai assez peu envie de faire appel à un script situé dans un autre fichier pour éviter d'avoir plusieurs fichiers à transférer en cas de mises à jour du script principal.
0
dubcek Messages postés 18718 Date d'inscription lundi 15 janvier 2007 Statut Contributeur Dernière intervention 22 mars 2024 5 615
7 juin 2012 à 10:08
en une seule commande:
bash -c 'for F in *.txt ; do ici code ed ou awk avec $F  ;done
- !! protéger les ' du code ed ou awk
-!! avec awk, il faut passer par un deuxième fichier
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Swiss Knight
7 juin 2012 à 10:58
Salut,
entre temps j'ai eu de l'aide ailleurs et ce bout de code :
awk 'BEGIN {OFS=","}
FNR == 1 { if( j==1 ) {
ligne[2]=ligne[2] OFS ligne[nb_lignes-1]
OFS ligne[nb_lignes]
for(i=1; i<=nb_lignes-2; i++) print
ligne[i] > nom_fic }
nom_fic=FILENAME
}
{ ligne[FNR]=$0; gsub(" ",",",ligne[FNR]);
nb_lignes=FNR; j=1 }
END { ligne[2]=ligne[2] OFS ligne[nb_lignes-1] OFS
ligne[nb_lignes]
for(i=1; i<=FNR-2; i++) print ligne[i] > nom_fic }'
*.txt 


ça marche assez bien aussi, le petit hic c'est qu'il faut que je sois dans le dossier contenant les fichiers, et que j'aimerai cibler cette commande sur un dossier préciser, mettons ~/username/data, et ce, peu importe oû je me situe dans l'arborescence.
0
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 407
7 juin 2012 à 13:50
Voilà une solution avec "sed" qui permet de cibler tous les fichiers d'un même répertoire et de modifier lesdits fichiers. L'option de sauvegarde "-i.bak" est facultative, mais permet néanmoins de faire un backup de chaque fichier.

J'ai créé 3 fichiers différents en nombre de "idxn" et de lignes intermédiaires afin de vérifier que tous les cas sont pris en compte.

$ head f*
==> f1 <==
lambda value idx1 idx2 caract
290 0.888
380 0.518
385 0.454
445 0.139
6.53 2.54
1.12

==> f2 <==
lambda value idx1 idx2 idx3 caract
290 0.888
380 0.518
385 0.454
445 0.139
550 0.122
6.53 2.54 1.23
1.12

==> f3 <==
lambda value idx1 idx2 idx4 idx5 caract
290 0.888
301 0.565
380 0.518
385 0.454
445 0.139
500 0.123
654 0.369
7.66 6.21 6.53 2.54 
1.12

$ cat script.sed 
1 {                                    
    N                                  
    h                                  
    d                                  
}                                      
:z                                     
N                                      
$ !b z                                 
s/(.*)\n(.*)\n(.*)/\2 \3\n\1/          
H                                      
g                                      
s/\n/ /2

$ sed -r -i.bak -f script.sed f*

$ head f*
==> f1 <==
lambda value idx1 idx2 caract
290 0.888 6.53 2.54 1.12
380 0.518
385 0.454
445 0.139

==> f1.bak <==
lambda value idx1 idx2 caract
290 0.888
380 0.518
385 0.454
445 0.139
6.53 2.54
1.12

==> f2 <==
lambda value idx1 idx2 idx3 caract
290 0.888 6.53 2.54 1.23 1.12
380 0.518
385 0.454
445 0.139
550 0.122

==> f2.bak <==
lambda value idx1 idx2 idx3 caract
290 0.888
380 0.518
385 0.454
445 0.139
550 0.122
6.53 2.54 1.23
1.12

==> f3 <==
lambda value idx1 idx2 idx4 idx5 caract
290 0.888 7.66 6.21 6.53 2.54  1.12
301 0.565
380 0.518
385 0.454
445 0.139
500 0.123
654 0.369

==> f3.bak <==
lambda value idx1 idx2 idx4 idx5 caract
290 0.888
301 0.565
380 0.518
385 0.454
445 0.139
500 0.123
654 0.369
7.66 6.21 6.53 2.54 
1.12

$ 
0
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 407
7 juin 2012 à 23:22
Au cas ou sur une seule ligne de commande :

sed -i.bak -r '1{N;h;d};:z;N;$!bz;s/(.*)\n(.*)\n(.*)/\2 \3\n\1/;H;g;s/\n/ /2' fic*
0