Working with Sed internal buffers

Hi,

I am using this simple command to copy the pattern buffer to hold buffer except for line 2, but it do not seems to work.

Line 2 when read by pattern buffer, is copied to hold buffer.

linux$ cat file1
a
b
c
linux$ sed '2!h;p' file1
a
a
b
b
c
c
/linux$ sed -n '2!h;p' file1
a
b
c

The p command prints the input buffer, not the hold buffer.
You can use one of the g G x commands to get the hold buffer to the input buffer.
To just print the hold buffer without modifying the input buffer you can use two x (swap) commands:

sed -n '2!h; x; p; x'

Without the -n option there is a default print of the input buffer at the end of each input cycle.

3 Likes

Thanks @MadeInGermany , for the help.

By Input buffer, I suppose you mean Pattern buffer ?

I need to understand it without -n option

This will be when we do not use any p command. But what when we explicitly prints using p.
3 more values are being added . what are these .

linux$ sed '2!h' file1
a
b
c

/linux$ sed '2!h;p' file1
a
a
b
b
c
c

man pages say pattern space, I say input buffer. Filled with one input line at the beginning of each cycle.
man pages say hold space, I say hold buffer. Filled by h H x commands.

A p command at the end of the sed code (script) prints the imput buffer, and the "default print" prints the inbut buffer again. So it is printed twice.

sed loops over the input, runs the code for each cycle.
At the beginning of a cycle one input line is put into the input buffer.
Then the code runs.
At the end of a cycle there is a "default print" of the input buffer, unless suppressed by a -n option.

I understand it like this:
with p it prints all lines of the file, along with a copy of the lines matching the pattern.

with -n, silence output; then use p to print only the lines matching pattern.

Hope this helps.

Please do not post screenshots of your code and data. Post the actual code, formatted with markdown.

Don't be lazy! Post formatted data and code. Show some respect for our time, please. We don't want to try to decode your screen shots.

Thank you!!

2 Likes

@MadeInGermany ,

As per your first reply,
Its clear to me at the point of '2!h;x;p' but when we again do x, the result should have been same as before swap, but:

Its not three line o/p as expected, as we haven't used p. So does that mean it is taking the last 3 values of input buffer along with present values.

For analytical understanding , I have put it like this:

input           hold                 default print                    explicit print
2!h;

a         >    a                       a                               a
b         >    a                       b                               b 
c         >    c                       c                               c
x;

a       ><    a                        a                              a
a       ><    b                        a                              a
c       ><    c                        c                              c

p;

a
a
a
a
c
c

x:

a      ><    a                          a                             a
b      ><    a                          b                             b
c      ><    c                          c                             c

But o/p is :

linux$ sed  '2!h;x;p;x' file1
a
a
a
b
c
c

expected :

a
a
b
b
c
c

I don't understand your perception.
Perhaps it becomes clear if you print the current input line number with =

sed  '=;2!h;x;p;x' file1

For each cycle

  • it reads one line into the input buffer, then
  • =prints the line number, then
  • 2!hconditionally copies to the hold buffer, then
  • x;p;xprints the hold buffer, and finally
  • it default-prints the input buffer.

Output is

1
a
a
2
a
b
3
c
c
2 Likes

Let me explain with the detailed comments as below. Here I have step-wise executed
2!h, then 2!h with p, then 2!h;x , then 2!h; x with p, up to which its pretty clear.

But as I do , 2!h; p; x; p , the first print should have o/p 6 lines , and the other p also 6 lines(total 12 lines), but o/p is 9 lines which I do not understand.

linux$ sed  '2!h' file1
a           (default print)
b           (default print)
c           (default print)

linux$ sed  '2!h;x;' file1
a           (default print)
a           (default print)
c           (default print)

linux$ sed  '2!h;p' file1
a           (default print)
a           (explicit print)
b           (default print)
b           (explicit print)
c           (default print)
c           (explicit print)

linux$ sed  '2!h;x;p' file1
a           (default print)
a           (explicit print)
a           (default print)
a           (explicit print)
c           (default print)
c           (explicit print)

l

inux$ sed  '2!h;p;x;p' file1
a
a
a
b
a
a
c
c
c

expected as :


a      (default print of 2!h)
a      (explicit print of 2!h for p after 2!h)
b      (default print of 2!h)
b      (explicit print of 2!h for p after 2!h)
c      (default print of 2!h)
c      (explicit print of 2!h for p after 2!h)
a      (default print of x)
a      (explicit print of x  for p after x)
a      (default print of x)
a      (explicit print of x for p after x)
c      (default print of x)
c      (default print of 2!h for p after x)

No, the default print is at the end of the sed code

sed  '2!h;p;x;p' file1
               ^

The sed code runs from left to right per input line:

  1. cycle: input buffer has a
  2. cycle: input buffer has b
  3. cycle: input buffer has c

This was unknown to me.

Thanks for helping. Now any operations may be understood well.

My Takeouts from this post which I was not aware of:

  1. p prints Internal buffer.
  2. Default is only shown in last p in case of multiple p .

Thanks UNIX.COM.

The p is always an explicit print.
The default-print happens at the end of the sed code.
The following are doing the same:

sed  '2!h;p;x;p' file1
sed -n '2!h;p;x;p;p' file1

Dito

sed  '2!h;p;x' file1
sed -n '2!h;p;x;p' file1
1 Like

As the extension of ongoing discussion, I just got that about the p option of regular sed operation of print (like substitute, quit , delete etc.) Is it a part of these buffer commands (H,h,G,g,x etc.) or in a different scope.
Does p here also works same, or it gives default o/p (rather than explicit) as we have to use p , if no other action is used.
This because when I used p in pattern matching with -n , then the o/p of p was suppressed.

$ sed  '/a/p' file1
a
a
b
c
linux$ sed  -n '/a/p' file1
a

This needs correction, was put incorrectly (I got that as to why you explained it once again) I need to say :

My Takeouts from this post which I was not aware of:

  1. p prints INPUT(Pattern) buffer.
  2. Default output is only shown in the last of sed .

Now it sounds correct.

Regarding the /a/, it is a line selector (or address) that behaves like an if clause. If the regular expression in // matches then run the following command, here a p.
Another one is a line number:
2p
If line 2 then print.
The selector can be negated by a following !
2!p
And
2!h
is: if not line 2 then copy to hold buffer.

You haven't said anything about my 2nd point. n is suppressing this p's output, though its not default.

After I put this , I realized this remains no more a question, as I understand that p is printing as per the condition and so p's output is not being really suppressed, but the default of the if condition , showing the internal buffer with all 3 lines.

I hope I have correctly understood.