Search code examples
macosbashsedgnubsd

can't get to understand the 'n' command of sed


I am trying to understand how the 'n' command of sed operates.

I am on Mac OS X, so it is sed from BSD

Let's consider this example :

$ seq 5 | sed -e 'n;p'
1
2
2
3
4
4
5

According to the Apple manpage here (see the quote below) and my understanding, the output should rather be this :

1
1
1
2
2
2
3
3
3
4
4
4
5
5
5

Apple manpage about sed :

[2addr]n

Write the pattern space to the standard output if the default output has not been suppressed, and replace the pattern space with the next line of input.

How I expect sed to manage this :

first cycle :

  • line 1 is read as input in pattern space (1)
  • then the 'n' command write the pattern space in stdout (1 is printed) since the default output as not been suppressed with the '-n' option
  • the 'p' command print the entire pattern space (1 is printed again)
  • default output is printed (1 is printed once again)

second cycle :

  • pattern space is cleared
  • line 2 is read as input in pattern space (2)
  • then the 'n' command write the pattern space in stdout (2 is printed)
  • the 'p' command prints the entire pattern space in stdout (2 is printed again)
  • default output is printed (2 is printed once again)

etc.

I also found this tutorial on (GNU ?) sed, but I didn't help me either to understand how this command line works (what does the '*' mean in the "Modification to Output Stream" column ?)

Can somebody explain to me what is going on step by step please ? Why some numbers are printed only once ? Is default output replace by the 'n' first function that is to write pattern space in stdout ? is pattern space really modified by 'n' or not ?


Solution

  • Thank you for the reference to my tutorial on sed, which was written for the original AT&T/Sun sed. I do my best to keep it up to date with the various extensions and variations, e. g. GNU sed.

    Don't forget, the 'n' command reads in the next line into the pattern space, which "flushes" the existing pattern space. The 'N" command doesn't "flush", but appends the pattern space.

    Here is what happens with the 'n;p' commands

    1. The next (in this case the first) line is read (which contains "1", and it put into the pattern space.
    2. The 'n' command is executed, which does the default, which in this case prints the pattern space, i.e. "1", and the 'n' is executed, reading the next line, so now "2" is in the pattern space, and nothing else is.
    3. The "p" command is executed, which prints the pattern space "2"
    4. After all of the commands are executed, sed does the default, which prints the pattern space (again), "2";

    Sed now repeats the above steps again. Which reads in "3", prints it, then reads in "4" and prints it twice, etc.

    If, for instance, you used

    seq 10 | sed -n -e 'n;p'
    

    then sed would print every other line. That is,

    1. Read next line into pattern space e.g "1"
    2. Execute the 'n' command, which puts "2" into the pattern space
    3. Execute the 'p' command which prints "2"
    4. Done with commands, now loop again, which will read in "3", then read "4", and print "4", etc.

    Does this help?

    And when I mention "modification to the output", it depends if the '-n' command line option is used or not. See the bottom of that chart.