3

I have a file like as follows

myname
_       something
_       something
_       something
myname
_       something
_       something
myname
_       something
and it follows and no standard other than myname word.

Now I want to print the first set of search from myname to till myname found as below.

myname
_       something
_       something
_

I tried using the following but it is not working.

sed -n -e '/myname/,/myname/ p' file

It prints all the sets.

Tried this also but not worked.

sed -n '/myname/,$ p;/myname/q'
tink
  • 14,342
  • 4
  • 46
  • 50
Sriharsha Kalluru
  • 1,743
  • 3
  • 21
  • 27

6 Answers6

4

Here is another way with awk:

awk '/myname/{++c}c<2' file

$ cat file
myname
_       something
_       something
_       something
myname
_       something
_       something
myname
_       something

$ awk '/myname/{++c}c<2' file
myname
_       something
_       something
_       something

If you file is too big then:

awk '/myname/{++c}c==2{exit}1' file
jaypal singh
  • 74,723
  • 23
  • 102
  • 147
  • @SriharshaKalluru You're welcome. Make sure you read this [answer](http://stackoverflow.com/questions/18407890/explain-awk-command/18409469#18409469). It contains many valuable gems! – jaypal singh Mar 09 '14 at 03:51
  • i think this only works if no lines exist prior to the 1st `myname`, cuz those extra lines would also get printed since `c == 0` for them, which satisifies `c < 2` – RARE Kpop Manifesto May 22 '23 at 17:36
2
awk  '/myname/{if(b) exit; else b=1}1' filename



$ cat temp.txt
myname
_       something
_       something
_       something
myname
_       something
_       something
myname
_       something

$ awk  '/myname/{if(b) exit; else b=1}1' temp.txt
myname
_       something
_       something
_       something
Amit
  • 19,780
  • 6
  • 46
  • 54
2
mawk '(_+=/myname$/)*_>_{ exit }_' 

 1  myname
 2  _       something
 3  _       something
 4  _       something
RARE Kpop Manifesto
  • 2,453
  • 3
  • 11
  • Can you please explain what you did there? :D – tink May 22 '23 at 17:50
  • @tink : it's basically the same idea, but I exit when `x < x^2`, something that fails for all values within `[0, 1]`, inclusive of both ends and all fractions in between, but passes for everyone else, so it'll exit when it increments to a 2. The final underscore `…}_` ensures it only starts printing after seeing the 1st `myname`, and ignore all lines prior to that – RARE Kpop Manifesto May 22 '23 at 21:46
  • @tink : and luckily for `awk`, the lack of actual boolean data type is a blessing in disguise, cuz it means instead of having to perform another layer of type conversions, all boolean conditions evaluate to numeric `0` or `1`, so I could directly `add` the outcome of the pattern evaluation, and make that my printing indicator flag. Unlike most shells or `perl`, the variable `_` is absolutely no special, so you can use it for anything – RARE Kpop Manifesto May 22 '23 at 22:05
  • Very impressive. I still don't fully understand what it all does - what's e.g. the point of that `*`? – tink May 22 '23 at 22:08
  • @tink : multiplication – RARE Kpop Manifesto May 22 '23 at 22:09
  • @tink : does this mapping help ? `((_ += /myname$/) * _) > (_) { exit } _` ::::::::::::::::::: `'/myname$/ { ++flag } flag < flag^2 { exit } flag != 0 { print }'` ::::::::::::: none of those are special obscure operators. they're just add-assign `+=`, `regex` pattern check against full input row `/…../`, multiplication `*`, greater than `>`, and the evaluation of a flag to invoke default print action block. – RARE Kpop Manifesto May 22 '23 at 22:12
  • Yes, it does help a lot :) Maybe you should include those explanatory words in the actual answer ... as it is it's about as legible as perl code ;) – tink May 22 '23 at 23:24
  • @tink : `perl` is a chaotic mess where `_` is reserved, having to say `my` this `my` that, user-defined functions couldn't be called `"functions"` but `"sub(routine)"` instead, `say` vs. `print` differ by barely anything, and the amount of quote or quote-like operators is beyond repair. – RARE Kpop Manifesto May 23 '23 at 00:00
1

This might work for you (GNU sed):

sed '/myname/{:a;n;//Q;$!ba}' file

Look for the pattern myname then set up a loop that, prints the current line, quits (but does not print) if the new current line contains the above pattern or loops.

An alternative, using the grep-like option -n:

sed -n '/myname/{:a;p;n;//q;ba}' file
potong
  • 55,640
  • 6
  • 51
  • 83
  • @ potong: this solution looks a good sed option , can you please elaborate how this command is working ? and what does //Q signify in between . – Vicky Jan 25 '17 at 13:42
  • @protong: From what I understand by //Q is an empty search expression with a 'quit' flag. Is it like when you pass an empty search expression it uses the last used search expression ( which is myname in this example ) ? as I used this sed '/myname/{:a;n;/myname/Q;$!ba}' and it also looks to be working the same way. – Vicky Jan 26 '17 at 02:10
  • 1
    @user3369871 [correct](https://www.gnu.org/software/sed/manual/sed.html#Regexp-Addresses) – potong Jan 26 '17 at 11:06
1

I have some sed only solutions for you:

Given this input file

$ cat file
myname
_       something
_       something
_       something
myname
_       something
_       something
myname
_       something
sed -n -e '/myname/,$ { 1,/myname/p }' file

produces this output

myname
_       something
_       something
_       something
myname

Adding | sed '$d' will delete the last line, so

sed -n -e '/myname/,$ { 1,/myname/p }' file | sed '$d'

gives this output

myname
_       something
_       something
_       something

Explanation

sed -n supresses line output /myname/,$ selects all the lines from myname to the end of the file.

From the selected lines { 1,/myname/p } will print all the lines to the next myname and finally | sed ‘$d’ deletes the last line of the previous command.

Obviously, this will also work where first and second regexs are different.

Bonus

sed -n -e '/myname/,$ { 1,/myname/ { /myname/!p } }' file

prints this:

_       something
_       something
_       something

Why the original selection isn’t working

Originally I couldn’t understand why your script wasn’t working. I had been trying something similar myself and had been searching for reasons why it wasn’t and just assumed that sed was, inexplicably, broken.

Then I realised: sed processes the whole file and applies your (and my!) patterns repeatedly, it finds several examples of myname … myname and prints all of them!

If the start and end /regexs/ are different then the expample below works (say your file had a mixture of myname and othername)

sed -n -e '/myname/,/othername/ { p; /othername/q }' file

You will still have to delete the last line of output if you don’t want the line containing othername.

Jack Chidley
  • 131
  • 9
0

Here is a Bash solution.

n=0
while read line; do
    [[ $line == myname ]] && ((n++))
    [ $n -gt 1 ] && break
    echo $line
done < file
John B
  • 3,566
  • 1
  • 16
  • 20