ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Maybe you could explain what you think should be printed? Seems to be working correctly to me.
The loop eventually exits. When it exits, there is a "p" instruction, at which point the pattern space ("1\n2\n3") must be printed. Yet nothing prints.
*edit*
I solved my problem. A better example would have been:
Code:
echo -e '1\n2\n3\n4' | sed -ne '/1/{;:loop;N;/^[^3]*$/b loop;p;}'
Although I'm still not clear on why the last instruction is skipped.
Although I'm still not clear on why the last instruction is skipped.
Maybe you could explain what you mean here? If by the last instruction you are referring to 'p', if it were skipped you would see nothing at all as you have used '-n'.
The reason I asked you to explain is so you could tell us what you think is happening in the script?
Your second is not a better example but rather one that has worked with the expression you have built. The idea is to build the expression to fit the data and not
the other way around (as the real world would have the data that needs to be manipulated)
Code:
echo -e '1\n2\n3\n4' | sed -ne '/1/,/3/{;:loop;N;/[^3]/b loop;p;}'
-n :- no output unless told to print (won't worry about -e as it serves no purpose)
/1/,/3/ :- only perform the following actions for lines in this range (ie. ignore the row with a 4 on it) { 1 is first number in pattern buffer }
:loop :- start of loop
N :- get the next line into the pattern buffer {pattern now holds '1\n2'}
/[^3]/b loop :- if pattern space contains something which is not a 3 redo loop (this true as pattern space does have a non-3 value in it, so go to start of loop)
N :- get the next line into the pattern buffer {pattern now holds '1\n2\n3'}
So your loop chews up all your data and by the time you get to 'p' there is nothing left to print
Whilst your second example works it is still not doing what you think. It continues the loop until the pattern buffer holds :- '1\n2\n3' and as a 3 is at the end which breaks
the loop from being true it then prints.
grail- I appreciate your detailed reply. I struggle with this comment:
Quote:
Originally Posted by grail
N :- get the next line into the pattern buffer {pattern now holds '1\n2\n3'}
So your loop chews up all your data and by the time you get to 'p' there is nothing left to print
I can see that all the data is consumed by the pattern buffer. However, I expect the pattern buffer to print when the loop exits and "p" executes. E.g. I don't see why the "p" is skipped in this case:
Code:
echo -e '1\n2\n' | sed -n '/1/{;:loop;N;/./b loop;p;}'
but not in this case:
Code:
echo -e '1\n2\n' | sed -n '/1/{;:loop;N;/^[^2]*$/b loop;p;}'
1
2
In both those cases the loop terminates with something (everything?) consumed by the buffer, so I think "p" should print something in both cases.
Or is the loop infinite in the first case, and sed simply times out without sending a failing exit status?
Yes the first gets to the end of the data and never meets the criteria set down so as it has reached the end of the file when it gets to the 'p' it has already
exhausted all the data so there is nothing to print. Whereas your second example gets to a situation where it is true that there is now a '2' before the end of the line
so it leaves the loop and progresses to the next instruction, ie. 'p'
As it reads inside the loop, the outside range specification /1/,/3/ isn’t used at all. It would only be used if the {} exits and a new record needs to be feed into the script.
I would phrase it more like: if 'N' cant read anything, execution will be stopped.
Bingo. That was ultimately the source of my problems (or more accurately: it was the thing preventing me from discovering my problems). Sed croaks when "N" runs out of food. This is mentioned on page 110 of "sed & awk" o'reilly 2nd ed. I suspect it's a crude protection from infinite loops. It's too bad this is not treated as an error condition. Exit status is normal.
It is treated as a normal exit as it reached the end of data but none of the expressions terms were met to result in output. This is not an error.
That is very true. Just because the last line has been read it does not mean that you always want to print it.
If the further execution of your script depends on some specific modifications that sed has done or not then you can set the exit status manually; this requires GNU sed, though.
It is treated as a normal exit as it reached the end of data but none of the expressions terms were met to result in output. This is not an error.
Correct, it's not an error -- that's actually the problem.
It's indeed a poor language choice to take a construct designed for data manipulation, and also give it flow control. It would be like creating a C "scanf" function that behaves like a goto statement in some obscure circumstances. And worse, these are circumstances that arise from inadvertent programming.
In fact having been burnt by this strange behavior and now knowing full well how "N" behaves, I would never deliberately use the N command for flow control. It would be an abuse; it would confuse other readers with poorly constructed code.
Sure, goto statements are appropriate for a quick and dirty language like sed, but this is effectively a goto nowhere -- that is, a goto without a destination label, and the goto statement itself is hiding within a construct that's used to move data.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.