4
votes

Comment fusionner plusieurs lignes en une seule ligne mais uniquement pour un bloc de lignes séparées par une ligne vide

J'essaie de fusionner plusieurs lignes en une seule mais avec des conditions supplémentaires.

Mon fichier d'entrée ressemble à:

awk '{printf("%s",$0)}' 

Il y a donc plusieurs lignes qui sont également séparés par des lignes vides. Tous les * trucs * contiennent des expressions longues et compliquées qui peuvent également contenir des parenthèses.

Je veux garder les lignes vides telles quelles mais fusionner les autres lignes multiples. H3 >

Le résultat attendu est

Dm1*(  stuff1 + stuff2 - stuff3 + stuff4)

+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 + D1stuff5 - D1stuff6 )

+ D2*(D2stuff)

Toutes les tentatives actuelles comme

Dm1*(  stuff1 + stuff2 -
stuff3 + stuff4)

+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +
  D1stuff5 - 
  D1stuff6 )

+ D2*(D2stuff)

mettent tout sur une seule ligne. Dois-je faire une boucle sur des lignes ou y a-t-il un moyen d'identifier les blocs entre les lignes vides et d'y appliquer quelque chose?


0 commentaires

6 Réponses :


2
votes

Essayez :

$ awk -v RS=  '{gsub(/ *\n */, " "); print $0 ORS}' file
Dm1*(  stuff1 + stuff2 - stuff3 + stuff4)

+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 + D1stuff5 - D1stuff6 )

+ D2*(D2stuff)

Comment ça marche:

  • -v RS =

    Cela indique à awk d'utiliser des lignes vides comme séparateurs d'enregistrements.

  • gsub (/ * \ n * /, "")

    Ceci dit à awk de remplacer toutes les nouvelles lignes dans l'enregistrement, ainsi que tous les espaces environnants, par un seul espace.

  • imprimer $ 0 ORS

    Cela indique à awk d'imprimer l'enregistrement suivi d'un séparateur d'enregistrement de sortie, ORS , qui, par défaut, est une nouvelle ligne.


0 commentaires

2
votes

En plus de la très belle commande awk introduite par John1024 , vous pouvez également utiliser une approche sed pour votre problème.

Entrée:

Dm1*(  stuff1 + stuff2 -stuff3 + stuff4)

+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +  D1stuff5 -  D1stuff6 )

+ D2*(D2stuff)

Commande:

sed -n '/^$/!{H};/^$/{x;s/\n//g;s/$/\n/;p;};${x;s/\n//g;p}' input_file

$ cat input_file 
Dm1*(  stuff1 + stuff2 -
stuff3 + stuff4)

+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +
  D1stuff5 -
  D1stuff6 )

+ D2*(D2stuff)

Explications: p>

  • -n désactiver l'impression automatique sed
  • / ^ $ /! {H}; Lorsque sed rencontre une ligne non vide / ^ $ /! ajoutez cette ligne à la conserver l'espace via H
  • / ^ $ / {x; s / \ n // g; s / $ / \ n /; p;} lorsque sed rencontre une ligne vide / ^ $ / , échangez l'espace de maintien et l'espace de motif x , supprimez tous les \ n dans la chaîne qui a été construite s / \ n // g , ajoutez un \ n à la fin de la chaîne s / $ / \ n / , imprimez-le p .
  • $ {x; s / \ n // g; p} lorsque sed atteint la dernière ligne, effectuez l'échange d'espaces hold / pattern x , puis supprimez tous les \ n via s / \ n // g avant de l'imprimer p .


0 commentaires

4
votes
awk '{if(NF!=0){printf $0}else{printf "\n\n"}}'

0 commentaires

6
votes

Encore un peu plus courte que la version de John1024

awk -v RS="" -v ORS="\n\n" '{$1=$1}1'

ou

awk 'BEGIN { RS=""; ORS="\n\n"}{$1=$1}1'

Utilisation de RS = "" code > dit à awk d'utiliser n'importe quel paragraphe comme enregistrement (c'est-à-dire un bloc de texte séparé par des lignes vides). Mais cela indique aussi à awk qu'un est toujours un séparateur de champ en combinaison avec FS . En redéfinissant simplement le séparateur d'enregistrement de sortie ORS , nous pouvons tout afficher comme vous le souhaitez en disant à awk de redéfinir son enregistrement $ 0 en réinitialisant le premier enregistrement $ 1 = $ 1 . Cela a pour effet que tous les séparateurs de champ définis par FS (la valeur par défaut ici) et les nouvelles lignes (dues à RS = "" ) sont remplacés par OFS (par défaut un ). Enfin, nous imprimons l'enregistrement avec 1

Vous pouvez vous débarrasser de tous les espaces en définissant en plus OFS=""

RS Le premier caractère de la valeur de chaîne de RS doit être le séparateur d'enregistrement d'entrée; a par défaut. Si RS contient plus d'un caractère, les résultats ne sont pas spécifiés. Si RS est nul , alors les enregistrements sont séparés par des séquences constituées d'une plus une ou plusieurs lignes vides, les lignes vierges de début ou de fin ne doivent pas donner lieu à des enregistrements vides à le début ou la fin de l'entrée, et un sera toujours un séparateur de champ, quelle que soit la valeur de FS .

source: POSIX awk standard


2 commentaires

il manque un ' dans la seconde avant {?


Oui, c'est la bonne façon / idiomatique de faire cela avec awk.



1
votes

Utilisation du mode paragraphe Perl

$ cat bogey.txt
Dm1*(  stuff1 + stuff2 -
stuff3 + stuff4)

+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +
  D1stuff5 -
  D1stuff6 )

+ D2*(D2stuff)
$ perl -00 -ne ' s/\n//g; print "$_\n\n" ' bogey.txt
Dm1*(  stuff1 + stuff2 -stuff3 + stuff4)

+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +  D1stuff5 -   D1stuff6 )

+ D2*(D2stuff)

$

avec vos entrées

perl -00 -ne ' s/\n//g; print "$_\n\n" ' file


0 commentaires

1
votes

Cela pourrait fonctionner pour vous (GNU sed):

sed ':a;N;/\n$/!s/\n//;ta' file

Rassemblez les lignes dans l'espace du motif, en supprimant les nouvelles lignes, jusqu'à ce qu'une ligne vide.


2 commentaires

cela fonctionne pour GNU sed. Cependant, je préfère quelque chose qui fonctionne à la fois sur les plates-formes GNU et BSD car j'utilise souvent les deux.


@Boogeyman Peut-être que sed $ ': a; N; / \\ n $ /! S / \\ n //; ta' file fonctionnera ou peut-être sed -e ': a' -e $ 'N; / \\ n $ /! \\ n //; ta' fichier