Comment merge des lignes avec un intervalle fixe dans un file?

J'ai un file et son contenu ressemble à ceci:

a1 b1 c1 aa bb cc aaa bbb ccc d1 e1 f1 dd ee ff ddd eee fff g1 h1 i1 gg hh ii ggg hhh iii 

Quelle est la meilleure façon de merge les lignes avec un intervalle fixe (3 dans ce cas) et get quelque chose comme:

 a1 aa aaa b1 bb bbb c1 cc ccc d1 dd ddd e1 ee eee f1 ff fff g1 gg ggg h1 hh hhh i1 ii iii 

L'algorithm pour get la sortie de l'input est:

  • D'abord, nous obtenons la ligne 1 qui est a1.
  • Nous soaps que l'intervalle est de 3
  • Donc rangée 1, rangée (1 + 3), rangée (1 + 3 + 3) devrait être sur la même rangée
  • De même, les rangées 2, 5, 8 devraient être sur la même rangée, etc.

Ceux a1 , aa et aaa etc. sont juste un text factice random et ils peuvent être n'importe quelle string random. Le point est qu'il existe un intervalle fixe entre a1 , aa et aaa .

Actuellement, j'utilise la macro keyboard emacs pour faire cette tâche. Cependant, je veux savoir s'il existe de meilleurs moyens de résoudre ce problème. Merci d'avance.

Si vous êtes sur gnu / n'importe quoi et que le nombre de lignes est multiple de 9, vous pouvez exécuter

 split -l9 --filter='pr -3 -s" " -t' infile 

Cela divise l'input en morceaux de neuf lignes et chaque pièce est canalisée à pr -3 -s" " -t' qui le colonne … Selon le no. de lignes et leur longueur, vous devrez peut-être jouer avec les options -w et -l . Voir la page de manuel pour plus de détails.

Voici une solution simplist dans awk, codée en dur pour extraire trois séries à trois lignes:

 { if (NR > 1 && (NR % 9) == 0) { print a "\n" b "\n" c " " $0 a="" b="" c="" } else if (NR % 3 == 1) { if (NR % 9 > 1) { a=a" "$0 } else { a=$0 } } else if (NR % 3 == 2) { if (NR % 9 > 2) { b=b" "$0 } else { b=$0 } } else { if (NR % 9 > 3) { c=c" "$0 } else { c=$0 } } } 

Enregistrez-le dans un file et exécutez awk -f thatfile < input . Je suis sûr qu'il y a des façons plus intelligentes de le faire, mais je ne travaille pas dans awk tous les jours.

C'est un peu difficile. Je ne connais pas un seul utilitaire qui puisse le faire:

Ce pipeline (essentiellement) lit 9 lignes à la fois et utilise pr pour formater en 3 colonnes:

 # there are 9 single hyphens below paste -d: -- - - - - - - - - - < file | while read line; do tr : '\n' <<<"$line" | pr -s" " -T -3 done 
 a1 aa aaa b1 bb bbb c1 cc ccc d1 dd ddd e1 ee eee f1 ff fff g1 gg ggg h1 hh hhh i1 ii iii 

Cela suppose que vous n'avez pas de deux points dans votre text actuel.

Un moyen très simple et clair dans TXR :

 @(repeat) @x0 @x1 @x2 @y0 @y1 @y2 @z0 @z1 @z2 @ (output) @x0 @y0 @z0 @x1 @y1 @z1 @x2 @y2 @z2 @ (end) @(end) 

Courir:

 $ txr reshape.txr data a1 aa aaa b1 bb bbb c1 cc ccc d1 dd ddd e1 ee eee f1 ff fff g1 gg ggg h1 hh hhh i1 ii iii 

Il y a des façons de condenser cela, mais vous devez travailler un peu plus fort pour les comprendre, par exemple:

 @(repeat) @ (collect :times 9) @line @ (end) @ (bind (xyz) @(tuples 3 line)) @ (output) @ (repeat) @x @y @z @ (end) @ (end) @(end) 

Aussi, voici comment quelqu'un qui sait quelque peu ce qu'ils font dans Awk pourrait mettre en œuvre:

  { a[(NR-1)%9] = $0 } !(NR%9) { print a[0], a[3], a[6] print a[1], a[4], a[7] print a[2], a[5], a[8] } 

Sortie:

 $ awk -f reshape.awk data a1 aa aaa [ ... ] i1 ii iii 

Et si ce codeur trouve des motifs d' print répétés répugnants:

  { a[(NR-1)%9] = $0 } !(NR%9) { for (i = 0; i < 3; i++) print a[i], a[i+3], a[i+6] } 

Solution TXR Lisp:

 [(opip (tuples 3) (tuples 3) (mappend transpose) (mapcar (aret `@1 @2 @3`)) tprint) (get-lines)] 

Courir:

 $ txr reshape.tl < data 

Sur la command line: utilisez -t , déposez le tprint :

 $ txr -t '[(opip (tuples 3) (tuples 3) (mappend transpose) (mapcar (aret `@1 @2 @3`))) (get-lines)]' < data 

Cela fonctionne en plaçant l'input à travers un pipeline qui le transforme en sortingplets, puis sortingplets de ces sortingplets (essentiellement des masortingces 3×3 faites de lists nestedes). Ces masortingces sont transposées individuellement et leurs lignes sont ensuite jointes set pour former une list géante de sortingplets. Ces sortingplets sont transformés en strings avec l'opérateur d'application partielle aret , une interpolation de string et une sortie avec tprint qui traite les lists de strings comme des lignes à sortir. La syntaxe

 (aret `@1 @2 @3`) 

se développe en quelque chose ressemblant

 (lambda (. args) (apply (lambda (arg1 arg2 arg3) `@arg1 @arg2 @arg3`) args)) 

Fondamentalement, il crée implicitement une fonction anonyme à un argument qui traite son argument comme une list d'arguments à appliquer à une fonction anonyme à 3 arguments où les @1 , @2 et @3 désignent les arguments. Le corps de la fonction est dérivé de l'expression quasi-string d'origine en substituant ces parameters numériques spéciaux par des noms d'arguments générés par la machine.

Pour le nom de file foo.txt.

sortinger foo.txt | coller – – –