akang
akang

Reputation: 651

Extract lines after a pattern

I have 50 files in a folder and all have a common pattern "^^". I want to print everything after "^^" and append the filename and print out all the extracted lines to one output file. While my code works fine with a single file it doesn't work on all the files.

awk '/\^^/{getline; getline; print FILENAME; print}' *.txt > output

Example

1.txt

     ghghh hghg 
       ghfg hghg hjg
            jhhkjh 
    kjhkjh kjh

^^ 
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

2.txt

hghjhg hgj 
 jhgj

            jhgjh kjgh

        jhg

^^ 
bbbbbbbbbbbbbbbbbbbbbbb

Desired output.txt

1.txt
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
2.txt
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

My actual output

1.txt
ghghh hghg
1.txt
zzzzzzzzzzzzzzzzzzzzzzzzzzzzz

Upvotes: 1

Views: 755

Answers (8)

potong
potong

Reputation: 58440

This might work for you (GNU sed):

sed -s '1,/^^^/{/^^^/F;d}' file1 file2 file3 ... >fileOut

Upvotes: 0

stevesliva
stevesliva

Reputation: 5665

Stealing from some answers and comments to your previous question on this topic, you can also use grep -A and format the output with sed.

$ grep -A100 '^^' *.txt | sed '/\^^/d;/--/d;s/-/\n/'
1.txt
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
2.txt
bbbbbbbbbbbbbbbbbbbbbbb

Assuming 100 lines is sufficient, and that you don't have hyphens of your own.

If you only need one line, use -A1

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 203684

$ awk 'FNR==1{print FILENAME; f=0} f; $1=="^^"{f=1}' *.txt
1.txt
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
2.txt
bbbbbbbbbbbbbbbbbbbbbbb

Upvotes: 1

user7712945
user7712945

Reputation:

let your files' name are 1 to 50 with txt type

for f in {1..50}.txt
{
  sed -nE "/^\^\^\s*$/{N;s/.+\n(.+)/$f\n\1/p}" $f>$f.result.txt
}

Upvotes: 0

Michael Back
Michael Back

Reputation: 1871

The following outputs only if we have a file that matches our pattern:

awk 'FNR==1 { f=0 }; f; /\^\^/ { f=1; print FILENAME }' *.txt > output
  1. Reset flag f on every new file.
  2. Print if f is set.
  3. Set f and print FILENAME if we match our pattern.

This one prints out the FILENAME regardless of matching pattern:

awk 'FNR==1 { f=0; print FILENAME }; f; /\^\^/ { f=1 }' *.txt > output

We can adjust the pattern matching in step 3 in accord with whatever is required... exact matching for instance can be done with $0=="^^".

Upvotes: 0

jxc
jxc

Reputation: 13998

use awk:

awk 'FNR==1{print FILENAME} FNR==1,/\^\^/{next}1' *.txt

Where:

  • print FILENAME when FNR == 1
  • FNR==1,/\^\^/{next}: all lines between FNR==1 and the first line matching ^^ will be skipped
  • 1 at the end to print the rest of lines after the matched ^^ line

Upvotes: 0

Aurium
Aurium

Reputation: 619

I like a more "bash(ish)" approach.

grep -Hn '^^' *.txt |
cut -d: -f1,2 --output-delimiter=' ' |
while read f n; do echo $f; tail $f -n+$((n+1)); done
  • grep -Hn will tell the line number of your pattern.
  • With cut we get only the needed fields, as we need.
  • In a loop we read the two informations into variables, to use they freely as we need.
  • The tail can read not only the last N lines, but also all lines from +N if you use the plus signal.
  • We can do arithmetic operation inside $((...)) to jump the pattern line.

And it solves your issue. And it can print all lines after the pattern, not only the next one.

Upvotes: 0

John1024
John1024

Reputation: 113864

To print the line after ^^, try:

$ awk 'f{print FILENAME ORS $0; f=0} /\^\^/{f=1}' *.txt
1.txt
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
2.txt
bbbbbbbbbbbbbbbbbbbbbbb

How it works:

  • f{print FILENAME ORS $0; f=0}

    If variable f is true (nonzero), print the filename, the output record separator, and the current line. Then set f back to zero.

  • /\^\^/{f=1}

    If the current line contains ^^, set f to one.

Upvotes: 1

Related Questions