2010-01-22 6 views
3

J'essaye de faire une analyse de chaîne assez simple dans le script bash. Fondamentalement, j'ai un fichier qui est composé de plusieurs champs multi-ligne. Chaque champ est entouré d'un en-tête et d'un pied de page connus.Plusieurs expressions regex multi-lignes dans Bash

Je veux extraire séparément chaque champ dans un tableau ou similaire, comme celui-ci

>FILE=`cat file` 
>REGEX="@#@#@#[\s\S][email protected]#@#@" 
> 
>if [[$FILE =~ $REGEX ]] then 
> echo $BASH_REMATCH 
>fi 

DOSSIER:

@#@#@################################# 
this is field one 
@#@#@# 
@#@#@################################# 
this is field two 
they can be any number of lines 
@#@#@# 

Maintenant, je suis assez sûr que le problème est que bash ne correspond pas à newlines avec le "."

Je peux faire correspondre cela avec "pcregrep -M", mais bien sûr le fichier entier va correspondre. Puis-je obtenir un match à la fois de pcregrep?

Je ne suis pas opposé à l'utilisation de Perl inline ou similaire.

Merci à l'avance

Répondre

3

si vous avez reluquer

awk 'BEGIN{ RS="@#*#" } 
NF{ 
    gsub("\n"," ") #remove this is you want to retain new lines 
    print "-->"$0 
    # put to array 
    arr[++d]=$0 
} ' file 

sortie

$ ./shell.sh 
--> this is field one 
--> this is field two they can be any number of lines 
+0

Modifié cela un peu pour faire ce que je veux. Awk est quelque chose que je n'ai jamais appris. Merci! – prestomation

0

Je construire quelque chose autour awk. Voici une première preuve de concept:

awk ' 
    BEGIN{ f=0; fi="" } 
    /^@#@#@#################################$/{ f=1 } 
    /^@#@#@#$/{ f=0; print"Field:"fi; fi="" } 
    { if(f==2)fi=fi"-"$0; if(f==1)f++ } 
' file 
0
begin="@#@#@#################################" 
end="@#@#@#" 
i=0 
flag=0 

while read -r line 
do 
    case $line in 
     $begin) 
      flag=1;; 
     $end) 
      ((i++)) 
      flag=0;; 
     *) 
      if [[ $flag == 1 ]] 
      then 
       array[i]+="$line"$'\n' # retain the newline 
      fi;; 
    esac 
done < datafile 

Si vous voulez garder les lignes de marquage dans les éléments du tableau, déplacez l'instruction d'affectation (avec son test de drapeau) au sommet de la boucle while avant la case.

1

La langue TXR effectue l'appariement multi-ligne entière-document lie les variables, et (avec l'option -B "liaisons de vidage") émette assignations de variables shell correctement échappées qui peuvent être eval -ed. Les tableaux sont pris en charge.

Le caractère @ est spécial, il doit donc être doublé pour correspondre littéralement.

$ cat fields.txr 
@(collect) 
@@#@@#@@################################# 
@ (collect) 
@field 
@ (until) 
@@#@@#@@# 
@ (end) 
@ (cat field)@# <- catenate the fields together with a space separator by default 
@(end) 

$ txr -B fields.txr data 
field[0]="this is field one" 
field[1]="this is field two they can be any number of lines" 

$ eval $(txr -B fields.txr data) 
$ echo ${field[0]} 
this is field one 
$ echo ${field[1]} 
this is field two they can be any number of lines 

La syntaxe @field correspond à une ligne entière. Ceux-ci sont rassemblés dans une liste puisqu'ils se trouvent dans un @(collect), et les listes sont collectées dans des listes de listes car elles sont imbriquées dans un autre @(collect). Le @(cat field) interne, cependant, réduit les listes internes à une seule chaîne, de sorte que nous nous retrouvons avec une liste de chaînes.

C'est « TXR classique »: la façon dont il a été conçu et utilisé, provoquée par l'idée:

Pourquoi ne pas faire ici-documents de travail en arrière et n'analyse de ramettes de texte en variables ?

Cette émission implicite des variables appariées par défaut, dans la syntaxe shell par défaut, continue d'être un comportement soutenu, même si la langue a connu une croissance beaucoup plus puissant, donc il y a moins d'un besoin d'intégrer des scripts shell .