Recherchez une chaîne et imprimez tout avant et après dans une plage


9

J'ai ce fichier:

sometext1{
string1
}

sometext2{
string2
string3
}

sometext3{
string4
string5
string6
}

Je veux rechercher dans ce fichier une chaîne spécifique et tout imprimer avant cette chaîne jusqu'à l'ouverture {et tout après cette chaîne jusqu'à la fermeture }. J'ai essayé d'y parvenir avec sed mais si j'essaie d'imprimer tout dans la gamme /{/,/string2/par exemple sed imprime ceci:

sometext1{
string1
}

sometext2{
string2
sometext3{
string4
string5
string6
}

Si je recherche la chaîne "string2", j'ai besoin que la sortie soit:

sometext2{
string2
string3
}

Merci.


Eh bien, maintenant, j'ai trouvé que j'avais besoin des numéros de ligne de la sortie dans le fichier d'origine pour les supprimer plus tard. J'ai essayé de changer la commande fournie par @mikeserv sans succès, je suis un peu confus avec la fonction hold de sed.
rodrigo

bien, bon sang, rodrigo, tu ne l'as dit à personne d'autre qu'à toi-même. cela peut être fait, mais il vaut mieux le faire comme grep -n '' <infile | sed .... Les sedcommandes devront être modifiées; en particulier les bits d' /adresse /qui recherchent ^des ancres haut de gamme. Donc, si vous utilisiez ma réponse que vous pourriez probablement faire: grep -n '' | sed 'H;/{$/h;/^[^:]*:}/x;/{\n.*PATTERN/!d'. Toutes les lignes de sortie seront préfixées avec les numéros de ligne du fichier d'origine suivis de deux points comme 1:sometext1{\n2:string1et ainsi de suite. sedfiltrera uniquement ce qu'il filtrerait auparavant, sauf que chaque ligne de sortie s'ouvre avec un numéro.
mikeserv

Réponses:


9

Voici deux commandes. Si vous voulez une commande qui coupe jusqu'à la dernière .*{$ligne d'une séquence (comme le fait @don_crissti avec ed), vous pouvez faire:

sed 'H;/{$/h;/^}/x;/{\n.*PATTERN/!d'

... qui fonctionne en ajoutant chaque ligne à l' Hancien espace à la suite d'un \ncaractère de ligne électronique, en écrasant l' hancien espace pour chaque ligne qui correspond {$, et en échangeant les hespaces anciens et de modèle pour chaque ligne qui correspond ^}- et ainsi vider son tampon.

Il n'imprime que les lignes qui correspondent à {puis à une ligne \nélectronique, puis PATTERNà un moment donné - et cela ne se produit que immédiatement après un échange de tampon.

Il supprime toutes les lignes d'une série de {$correspondances à la dernière de la séquence, mais vous pouvez obtenir toutes ces inclusions comme:

sed '/PATTERN.*\n/p;//g;/{$/,/^}/H;//x;D'

Ce qu'il fait est de permuter le motif et les hanciens espaces pour chaque ...{$.*^}.*séquence, ajoute toutes les lignes de la séquence à l' Hancien espace après un \ncaractère Dewline et se termine jusqu'au premier \ncaractère ewline apparaissant dans l'espace modèle pour chaque cycle de ligne avant de recommencer avec ce qui reste.

Bien sûr, la seule fois où il obtient une ligne \nélectronique dans l'espace de motif, c'est lorsqu'une ligne d'entrée correspond ^}- la fin de votre plage - et donc lorsqu'elle réexécute le script à toute autre occasion, elle tire simplement la ligne d'entrée suivante par habitude.

Quand PATTERNest trouvé dans le même espace de motif qu'une ligne \nélectronique, cependant, il imprime le lot avant de l'écraser à ^}nouveau (afin qu'il puisse mettre fin à la plage et vider le tampon) .

Compte tenu de ce fichier d'entrée (merci don) :

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}
}

Les premiers tirages:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

...et le deuxième...

sometext2{
PATTERN
string3
}
Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

@don_crissti - Je ne sais pas. Il délimite uniquement la séquence d'une ligne commençant par }. Cela pourrait être bénéfique pour ... open{\nsub;\n{ command; }\n}; close- mais je ne suis pas sûr que ce soit le cas ici ...
mikeserv

Salut @mikeserv - J'ai une question similaire qui est soulevée ici unix.stackexchange.com/questions/232509/… , votre solution fonctionne sur un petit fichier, mais j'ai un gros fichier et je reçois "Espace de stockage débordé". Message d'erreur. Avez-vous une chance, comment pourrais-je résoudre ce problème? Merci beaucoup
Narayan Akhade

@ NarayanAkhade - non. pas sans révision, de toute façon. sauf ... y a-t-il de grandes étendues d'entrée qui ne sont pas contenues dans des {...}blocs? Si c'est le cas et que vous utilisez la première solution, vous pouvez le faire /{$/,/^}/Hau début au lieu de simplement H. Mais si vous avez également essayé la deuxième solution et que vous rencontrez toujours la même erreur, il est peu probable que cela aide, car celle-ci le fait déjà. Et ne remettez pas non edplus. don a une très bonne réponse ici, et edpeut également être utilisé pour utiliser des fichiers tampons temporaires très simplement, ce qui devrait empêcher les dépassements de tampon mem.
mikeserv

6

Voici une solution avec ed:

ed -s filename <<< $'g/PATTERN/?{?,/}/p\nq\n'

C'est:

g/PATTERN/     # mark each line matching PATTERN  
?{?,/}/p       # for each marked line, print all lines from the previous { up to the next }  
q              # quit editor

Cela suppose qu'il n'y a qu'une seule ligne PATTERNentre chaque paire, { }sinon vous obtiendrez une sortie en double pour chaque ligne supplémentaire à l' PATTERNintérieur du même bloc.
Cela fonctionnera pour plusieurs { }contenant une seule ligne correspondant PATTERNpar exemple pour un fichier de test avec PATTERNdans deux sections différentes:

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN again

another string here
}
}

fonctionnement

ed -s sample <<< $'g/PATTERN/?{?,/}/p\nq\n'

les sorties:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN again

another string here
}

En fait, j'en ai beaucoup retiré! Merci beaucoup!
mikeserv

Je ne sais même pas que cette commande existe. Merci
rodrigo

4

Avec pcregrep:

pcregrep -M '(?s)\{[^}]*PATTERN.*?\}'

Ou avec GNU à grepcondition que l'entrée ne contienne pas d'octets NUL:

grep -Poz '.*(?s)\{[^}]*PATTERN.*?\}'

0
$ awk 'BEGIN{RS="\n\n"; FS="[{}]"} {if ($2 ~ /string4/) {print $2}}' t1.txt
string4
string5
string6

où:

  • string4 -> chaîne à associer
  • t1.txt -> contient le contenu du fichier mentionné dans la requête

-2

sed -n '/ string / p' nom de fichier

le -n lorsqu'il est ajouté au comportement par défaut de sed a supprimé sed cette déclaration peut ne pas vous donner exactement ce que vous voulez mais elle devrait juste déplacer la chaîne

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.