Comment lire certaines lignes après avoir trouvé du texte?

12

Comment puis-je lire un certain nombre de lignes après avoir trouvé du texte?

Par exemple.:

Lisez les 2 lignes suivantes après avoir trouvé "Unix" sur:

Test 1
Test 2
Test 3
Test 4
UNIX
Test 5
Test 6
Test 7
Test 8
Test 9

Le résultat peut être:

Test 5
Test 6

Remarque: "Unix" sur le dernier exemple est un argument, et ainsi, il peut s'agir de n'importe quel autre texte.

Ce que j'ai:

Je suis toujours à court d'idées, j'ai juste besoin d'une lumière. Penser à créer un autre script pour ce faire.

Du froid
la source

Réponses:

10

Une awksolution:

$ awk '$0 == "UNIX" {i=1;next};i && i++ <= 2' file
Test 5
Test 6

Explication

  • /^UNIX$/{i=1;next}: si nous voyons UNIX, nous définissons variable i = 1, le traitement à la prochaine entrée.

  • Si la variable iest définie (ce qui signifie que nous l'avons vu UNIX), elle i && i++ <= 2n'est évaluée que sur la valeur vraie dans les deux lignes suivantes UNIX, ce qui provoque l' awkaction par défaut effectuée print $0.

  • Avant de voir UNIX, in'était pas défini et commençait à la 3ème ligne après UNIX, iavait une valeur supérieure à 2, ce qui rend l'expression i && i++ <= 2évaluée à faux, awkne provoquant rien.

cuonglm
la source
Après le test, votre solution im reçoit ce message d'erreur: erreur systax près de la ligne 1 renflouant près de la ligne 1
Froid
@Cold: Qu'avez-vous couru? Veuillez noter que le $signe au début de ma réponse est l'invite du shell, ne fait pas partie de la awkcommande.
cuonglm
Autre variante:awk '/^UNIX$/ {s=NR;next} s && NR<=s+2'
musiphil
Je sais que @cuonglm
Cold
@Cold: Quel est votre système d'exploitation?
cuonglm
12

Une grepsolution:

grep -A2 -P '^UNIX$' file

Explication: -A signifie: imprimer les deux lignes suivantes après la correspondance

Ou awk:

awk '$0=="UNIX"{getline; print; getline; print}' file

Explication: Cette instruction recherche UNIX dans la ligne ( $0=="UNIX"). Si cela est donné, il obtient le suivant dans son buffer ( getline) et imprime le buffer ( print). Cela se fait deux fois.

Ou utilisez sed:

sed -n '/^UNIX$/{n;p;n;p}' file

Explication: cela recherche UNIX ( /^UNIX$/). S'il est trouvé, il exécute la pièce dans le fichier {...}. nsignifie ensuite, psignifie imprimer. Cela se fait également deux fois.

le chaos
la source
Merci @chaos, je vais essayer les 2 dernières options que vous donnez. Veuillez ajouter quelques explications sur chaque option, je vais comprendre et faire.
Cold
Si le nombre de lignes change, combien de modifications vais-je apporter aux deux dernières options? Merci
Cold
@Cold voir ma modification. Pour modifier le nombre si les lignes répètent la getline; print;partie de l' awkinstruction ou la n;p;partie de l' sedinstruction.
chaos
Merci @chaos, mais plus le nombre de lignes augmente l'expression et le changement n'est pas réalisable à mon avis. Ne penses tu pas? Si 100 lignes?
Froid
@Cold Ensuite, j'utiliserais la solution grep avec grep -A100 -P '^UNIX$' file | tail -n +2. La partie arrière consiste à supprimer le premier privilège. Dans les autres (sed, awk), il faudrait écrire des boucles, ce qui le rend moins simple.
chaos
4
grep -A 2 UNIX file.txt

La page de manuel de grep décrit ainsi l'option:

  -A NUM, --after-context=NUM
      Print NUM  lines  of  trailing  context  after  matching  lines.
      Places  a  line  containing  --  between  contiguous  groups  of
      matches.
Scintille
la source
Salut @Twinkles, bonne réponse, mais mon grep n'a que cette option "hblcnsviw". Mais la logique est bonne. merci
Cold
Cela s'imprimera également UNIXen sortie.
cuonglm du
Pour omettre la UNIXpipe à tail: [...] | tail -n +1ou à sed: [...] | sed '1d'.
DopeGhoti
1
@DopeGhoti: vos suggestions tailet ne sed '1d'fonctionnent correctement que si UNIXn'apparaît qu'une seule fois dans le texte saisi. Toutes les autres réponses permettent plusieurs occurrences. Il serait peut-être préférable de suggérer ... | grep -v UNIX. Certes, cela devient désordonné si UNIXapparaît sur les lignes 15 et 17.
G-Man dit 'Reinstate Monica'
Bons points. Je suis à peu près sûr que cela pourrait être fait sedavec une certaine forme de sed '/UNIX/d;n;n;p/' /path/to/file, que je viens d'évoquer et de soumettre comme réponse.
DopeGhoti
0

Cela semble bien faire l'affaire:

sed -n '/UNIX/{n;p;n;p}' /path/to/file

Preuve de concept:

$ for i in {1..9}; do echo $i; done | sed -n '/4/{n;p;n;p}'
5
6
DopeGhoti
la source
1
Le sous-shell autour de votre forboucle n'est pas nécessaire.
pause jusqu'à nouvel ordre.
En effet, ce n'est pas le cas; c'était un vestige de quelque autre faffery que j'étais au milieu de cet obus plus tôt dans la journée. Parens supprimés.
DopeGhoti
0

Vous pouvez utiliser ex:

ex -s +'1,/UNIX/d|%p|q!' file_or_/dev/stdin

où:

Kenorb
la source