[BASH] awk, le premier cercle de l'enfer

Bonjour la zone,

Je viens vers vous pour un problème d’algo un peu con mais qui commence à me bouffer le crâne. Je dois faire de la mise en forme de fichiers texte (pour convenir à un format d’entré d’un soft particulier), j’ai choisi d’effectuer l’ensemble des manips en BASH (le tout étant éxécuté à partir d’un code python générant les fichiers texte sur lesquelles je veux effectuer les manips).

Mais voilà, parfois la vie c’est pas le paradis.

Je veux transformer ça :

0102
0304
0506
0708
0910
1112

en ça :

0102 0304 0506
0708 0910 1112

Pour ce faire, j’utilise la commande « awk » (qui est un langage en elle-même), et j’obtiens ça :

awk ‹ NR<=3{a[0]=a[0] " " $1}END{for (i in a){print a[i]}} › ./test.tmp

La démarche étant de stocker dans un tableau les valeurs de trois lignes (plus l’espace qui va bien) et d’afficher le tableau. C’est assez convaincant puisque cela marche pour les trois premières lignes MAIS pas moyen de faire en sorte que cela boucle sur l’ensemble du fichier (sur les 3 dernières lignes dans l’exemple).

Quelqu’un aurait une petite idée pour que cette opération s’effectue toutes les trois lignes ?

J’espère que je suis clair,

Merci d’avance :slight_smile:

Pour moi, c’était pas la bonne méthode, je ferais comme ça:
`BEGIN { count=0; }
{
if (count==2)
{
count=0;
printf("%s\n",$0);
}
else
{
printf("%s ",$0);
count++;
}

}
`
Ça me parait plus simple
(désolé pour le format mais bon)
Note: dans mon souvenir, python fait ce genre de truc nativement mais j’ai jamais programmé en python donc… :wink:

Le scripting facile avec awk

2 « J'aime »

Merci beaucoup LoneWolf, ça marche parfaitement ! :smiley:

J’ai essayé de faire quelque chose comme ça mais c’était pas vraiment concluant…

Là, c’est parfait, c’est plus intuitif en plus ! :stuck_out_tongue:

Où comme ça:

$ cat input.txt 0102 0304 0506 0708 0910 1112 1345 3450 3278 1465 6754 9876 6666 $ cat input.txt | paste -s -d ' ' - | fold -w15 | sed -e 's/ *$//' 0102 0304 0506 0708 0910 1112 1345 3450 3278 1465 6754 9876 6666 $

En gros on remplace tous les sauts de ligne par des espaces, on split tous les 15 caractères et on s’assure de virer l’espace qui reste en fin de ligne

4 « J'aime »

Vous etes des malades :slight_smile:

1 « J'aime »

Peut-être que @Ivru pourrait nous donner la REGEX qui va bien? ^^

SkullyFM, effectivement c’est une autre façon de faire ! J’avais pas pensé à compter les caractères…

Mais sachant que je travail sur plein de “gros” fichiers, je préfère utiliser awk et éviter les cat, ça trace plus !

Le cat c’est juste pour montrer comment utiliser l’entrée standard. Si tu veux utiliser des fichiers la commande serait:

paste -s -d ' ' input.txt | fold -w15 | sed -e 's/ *$//'

Edit: mais la solution de @LoneWolf est probablement plus rapide vu que c’est 100% awk.
J’en ai profité pour la mettre en forme:

awk 'BEGIN {count=0;} {if (count==2) {count=0;printf("%s\n",$0);} else {printf("%s ",$0); count++;}}' ./input.txt

Non mais les regex en multi-line, c’est comme la kro sans picon : no way! (on est dredi 19h30…)

C’est quand même de la haute voltige la :slight_smile:
En traitement de fichier texte, sed est efficace sur les choses simple mais pas super pratique des qu’il s’agit de gérer des retour chariot. Pis bon, awk, c’est un langage de programmation quoi :slight_smile:
Après, je saurais pas dire quelle solution est la plus efficace mais je trouve ma version plus simple, et comme je suis une feignasse… :wink:

Les informaticiens sont des flemmards de ouf :slight_smile:

Mais pourquoi tu ne le fais pas en python à ce moment là ?

Par exemple avec les lambdas expressions et les listes ? :stuck_out_tongue:

Quand on veut faire du shell on assume :stuck_out_tongue:

Bon, j’ai trouvé une version simple et lisible:

$ paste -d ' ' - - - < input.txt 0102 0304 0506 0708 0910 1112 1345 3450 3278 1465 6754 9876 6666 $

1 « J'aime »

Punaise, je découvre des commandes tous les jours:

$ pr -3at -s" " input.txt 0102 0304 0506 0708 0910 1112 1345 3450 3278 1465 6754 9876 6666 $

3 « J'aime »

Tout simplement parce que je pense que c’est plus simple de le faire en bash (peut être plus rapide aussi) ! J’ai fait plein d’autres manips avant (en awk), et je préfère rester dans le même registre :slight_smile: Le python est vraiment pratique pour ça, tu peux incruster des scripts écrits avec d’autres langages super facilement.

SkullyFM, merci, maintenant j’ai plein de choix :wink:

C’est vraiment un truc de grand malade awk et la ligne de commande…

1 « J'aime »

Quand je pense que j’ai fait une petite mission de migration de conversion de tout les scripts bash/sed/awk en scripts python :smiley: . Ben j’avais vraiment eut du mal à décortiquer la partie awk même si j’ai fini par y arriver en vérifiant que mes fichiers cibles étaient exacts :slight_smile:

Pour le fun, en python, on fait ça :

[item for item in zip(*[iter(string.split())]*3)]

Où string est la liste des entiers donnée en début de thread. :smiley:

1 « J'aime »

Anaethelion, ça a de la gueule :slight_smile:

J’ai deux petites questions encore :

  • J’ai plusieurs scripts en python, dont un fichier principal à partir duquel j’éxecute les autres. Au niveau des import de packages, je peux les mettre uniquement dans ce « main » ou il faut les notifier dans tous les scripts ?

  • Dans une commande sed toute conne, je voudrais ajouter une variable du style :
    sed ‹ 0~VARG › ./file.txt, ou VAR est définie au préalable dans le script, mais sed ne permet pas de définir des variables comme awk apparement. Cette commande permet de sauter une ligne toutes les VAR lignes. Si quelqu’un à une idée :slightly_smiling:

Je suis perplexe, tu peux pas avoir plusieurs main dans un programme donc si tu as plusieurs « scripts » qui ont des fonctions ça devient des bibliothèques que tu importes dans ton main pour orchestrer les appels. En toute logique.

Si c’est pas clair on peut passer en MP si t’as besoin d’aide. :slightly_smiling:

[edit]

Si t’importes tout dans tous les sens tu vas finir avec une dépendance circulaire des familles lopez.