Conversion de lignes en morceaux en fichiers délimités par des tabulations

J’ai les lignes suivantes en 2 morceaux (en fait il y a ~ 10K de cela). Et dans cet exemple, chaque segment contient 3 lignes. Mais en réalité c’est 6 lignes.

xox 91-233 chicago koko 121-111 alabama 

Je veux le transformer en

 xox 91-233 chicago koko 121-111 alabama 

Comment puis je faire ça?

J’ai essayé tr "\n" "\t" mais ne fait pas ce que je veux.

 $ awk -F'\n' '{$1=$1} 1' RS='\n\n' OFS='\t' file xox 91-233 chicago koko 121-111 alabama 

Comment ça marche

Awk divise l’entrée en enregistrements et divise chaque enregistrement en champs.

  • -F'\n'

    Cela indique à awk d’utiliser une nouvelle ligne comme séparateur de champs.

  • $1=$1

    Ceci indique à awk d’atsortingbuer le premier champ au premier champ. Bien que cela ne fasse apparemment rien, cela amène awk à traiter l’enregistrement comme modifié. Par conséquent, la sortie est imprimée en utilisant notre valeur atsortingbuée pour ORS , le séparateur d’enregistrement de sortie.

  • 1

    C’est un raccourci crypté d’Awk pour imprimer la ligne.

  • RS='\n\n'

    Ceci indique à awk de traiter deux nouvelles lignes consécutives comme séparateur d’enregistrements.

  • OFS='\t'

    Cela indique à awk d’utiliser un onglet comme séparateur de champs en sortie.

une autre alternative,

 $ sed '/^$/d' file | pr -3ats$'\t' xox 91-233 chicago koko 121-111 alabama 

Supprimez les lignes vides avec sed et imprimez-les sur 3 colonnes avec un séparateur de tabulation. Dans votre vrai fichier, cela devrait être le nombre de lignes dans les blocs.

Notez que cela ne fonctionnera que si tous vos blocs ont la même taille.

Cette réponse offre les éléments suivants:
* Il fonctionne avec des blocs de lignes non vides de toute taille, séparés par un nombre quelconque de lignes vides; La réponse utile de John1024 (qui est similaire et est venue en premier) fonctionne avec des blocs de lignes séparés par une seule ligne vide.
* Il explique la commande awk utilisée en détail.

Une solution awk plus idiomatique (conforme à POSIX):

 awk -v RS= -F '\n' -v OFS='\t' '$1=$1""' file 
  • -v RS= demande à awk de fonctionner en mode paragraphe : considérez chaque série de lignes non vides comme un enregistrement unique ; RS est le séparateur d’ enregistrement en entrée.

    • Remarque: la conséquence est que cette solution considère une ou plusieurs lignes vides comme séparant les paragraphes (blocs de lignes); empty signifie: pas de caractères internes à la ligne, pas même les espaces.
  • -F '\n' indique à awk de considérer chaque ligne d’un paragraphe d’entrée comme son propre champ (divise l’enregistrement d’entrée multiligne en champs par lignes); -F définit FS , le séparateur de champ d’ entrée.

  • -v OFS='\t' indique à awk de séparer les champs avec \t (caractères de tabulation.) en sortie ; OFS est le séparateur de champs de sortie.

  • $1=$1"" ressemble à un no-op, mais, en raison de l’ affectation à la variable de champ $1 (le premier champ de l’enregistrement), awk demande à reconstruire l’enregistrement d’entrée, en utilisant OFS comme séparateur de champ, remplaçant ainsi efficacement les séparateurs avec \t .

    • La fin "" est de se protéger contre la casse de la première ligne dans un paragraphe évaluant à 0 dans un contexte numérique; append "" force le traitement comme une chaîne , et toute chaîne non vide – même si elle contient "0" – est considérée comme vraie dans un contexte booléen – voir ci-dessous.
  • Étant donné que $1 est par définition non vide et que les affectations dans awk passent par leur valeur, le résultat de l’affectation $1=$1"" est également une chaîne non vide; Comme l’assignation est utilisée comme modèle (une condition) et qu’une chaîne non vide est considérée comme vraie , et qu’il n’y a pas de bloc d’ action associé ( { ... } ), l’ action implicite consiste à imprimer l’enregistrement – reconstruit – se compose maintenant des lignes d’entrée séparées par des tabulations , terminées par le séparateur d’enregistrement de sortie par défaut ( ORS ), \n .

 xargs -L3 < filename.log |tr ' ' '\t' xox 91-233 chicago koko 121-111 alabama 

une autre version de awk pour le faire

  awk '{if(NF>0){a=a$1"\t";i++};if(i%3==0&&NF>0){print a;a=""}}' input_file