2009-04-16 13 views
6

Pour ajouter une ligne vide au-dessus de chaque ligne qui correspond à votre regexp, vous pouvez utiliser:Shell: insérer une ligne vide/nouveau deux lignes ci-dessus modèle

sed '/regexp/{x;p;x;}' 

Mais je veux ajouter une ligne vide, pas un ligne ci-dessus, mais deux lignes au-dessus de la ligne qui correspond à mon expression rationnelle.

Le motif que je vais apparier est un code postal dans la ligne d'adresse.

Voici un extrait de mise en forme du texte:

information aléatoire (appartient entreprise précédente)
nom commercial
adresse commerciale

Par exemple:

Langues parlées: Anglais
Cove Arnold, T.-N. (sous Clarenville)
route du Nil, Arnolds Cove, NL, A0B1N0

Je voudrais ajouter une nouvelle ligne au-dessus du nom de l'entreprise:

Langues parlées: Anglais

Cove Arnold, T.-N. (sous Clarenville)
route du Nil, Arnolds Cove, NL, A0B1N0

Répondre

5

Quelque chose un peu comme votre approche originale dans sed:

sed '/regexp/i\ 

$H 
x' 

L'idée de base est d'imprimer tout retardé d'une ligne (x changer les espaces de maintien et motif - l'impression est implicite) . Cela doit être fait car jusqu'à ce que nous vérifions si la ligne suivante correspond à l'expression rationnelle, nous ne savons pas si ou nsert une nouvelle ligne ou non.

(Le $ H il y a juste un truc pour faire la dernière impression en ligne Il ajoute la dernière ligne dans la mémoire tampon de maintien de sorte que les résultats finaux de commande d'impression implicite aussi..)

+0

Il imprime une ligne vide avant toutes les lignes. –

+0

Oui, il imprime une ligne vide au début, car il affiche le contenu de l'espace de stockage pour toutes les lignes, ce qui est vide pour la première ligne. Ajout de '1d' comme la dernière commande se débarrasse de cela. –

+0

... ainsi que d'éliminer toutes les sorties si l'entrée est longue d'une seule ligne. – ephemient

0

J'ai essayé

sed '/regexp/a\\n' 

mais il a inséré deux nouvelles lignes. Si cela ne vous dérange pas, prenez-le.

echo -e "a \ nb \ nc" | sed '/^a $/a \ n'
un

b
c

Edit: Maintenant que vous déclarez que vous devez insérer deux lignes au-dessus du regexp correspondant le suggère regex ne fonctionnera pas.

Je ne suis même pas sûr que cela fonctionnerait du tout avec sed, car vous devez vous souvenir des lignes précédentes. Cela ressemble à un travail pour un langage de niveau supérieur comme python ou perl :-)

+0

qui insère deux nouvelles lignes ci-dessous le modèle ... – Dennis

+0

Eh oui, c'est ce que je l'ai dit :-) – lothar

+0

Merci, je vais modifier ma question d'inclure les balises Python et Perl (je connais un peu de Python et pas Perl, donc malheureusement je suis toujours coincé.) – Dennis

1

Voici une approche qui fonctionne pour Python.

import sys 
def address_change(aFile): 
    address= [] 
    for line in aFile: 
     if regex.match(line): 
      # end of the address 
      print address[0] 
      print 
      print address[1:] 
      print line 
      address= [] 
     else: 
      address.append(line) 
address_change(sys.stdin) 

Cela vous permet de reformater une adresse complète au contenu de votre cœur. Vous pouvez développer ceci pour créer une classe Address si votre formatage est complexe.

2
perl -ne 'END{print @x} [email protected],$_; if(@x>2){splice @x,1,0,"\n" if /[[:alpha:]]\d[[:alpha:]]\s?\d[[:alpha:]]\d/;print splice @x,0,-2}' 

Si je chat votre fichier dans, je reçois ce que tu veux ... il est laid, mais vous vouliez shell (c.-à-un-liner) :-) Si je devais le faire en perl plein, Je serais capable de le nettoyer beaucoup pour le rendre lisible. :-)

7

Plus lisible Perl, et gère plusieurs fichiers sainement.

#!/usr/bin/env perl 
use constant LINES => 2; 
my @buffer =(); 
while (<>) { 
    /pattern/ and unshift @buffer, "\n"; 
    push @buffer, $_; 
    print splice @buffer, 0, -LINES; 
} 
continue { 
    if (eof(ARGV)) { 
     print @buffer; 
     @buffer =(); 
    } 
} 
3

simple:

sed '1{x;d};$H;/regexp/{x;s/^/\n/;b};x' 

décrire

#!/bin/sed 

# trick is juggling previous and current line in hold and pattern space 

1 {   # at firs line 
    x   # place first line to hold space 
    d   # skip to end and avoid printing 
} 
$H   # append last line to hold space to force print 
/regexp/ { # regexp found (in current line - pattern space) 
    x   # swap previous and current line between hold and pattern space 
    s/^/\n/ # prepend line break before previous line 
    b   # jump at end of script which cause print previous line 
} 
x   # if regexp does not match just swap previous and current line to print previous one 

Modifier: Un peu version plus simple.

sed '$H;/regexp/{x;s/^/\n/;b};x;1d' 
+0

Salut Hynek, je l'ai essayé et ça marche, mais pouvez-vous l'expliquer? – Dennis

+0

Ne contient que deux lignes en mémoire. Ligne précédente dans l'espace de maintien et ligne courante dans l'espace de motif. Lorsque regexp est trouvé, ajoutez juste une nouvelle ligne à 'hold space'. –

+0

Si l'entrée n'est longue qu'une seule ligne, ceci n'imprime malheureusement rien du tout. – ephemient