Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

i was just going thorugh this and i was unable to understand.

sed -n '1h; 1!H; ${ g; s/foo\nbar/bla\nblub/ p }' file.

where cat file is :

 foo
 foo
 bar

why there is 1!H because to me 1h overwrites the pattern space and 1!H is of no use

But the sed one liner seems to work fine.

share|improve this question
add comment

2 Answers

up vote 7 down vote accepted

See @manatwork's answer for the actual reason for 1h;1!H, but I wanted to add a portability note.

The standard and portable syntax should be:

sed -n '1h; 1!H; ${ g; s/foo\nbar/bla\
blub/p;}'

Otherwise it won't work in most sed implementations, for instance the traditional Unix ones.

That is \n is understood on the left hand side of the s command, but you have to use a backslash character followed by an actual newline character on the right hand side. You also need the ; between the s command and }, and no space before the p.

You could also store the content of the file in the pattern space instead of the hold space:

sed -n '
  :1
  $!{
   N;b1
  }
  s/foo\nbar/blah\
blup/p'

But with both pattern and hold space, with most sed implementations that will only work with small files as most non-GNU implementations have a limited size for those (and POSIX only requires them to be able to hold 8kiB of data).

Portably, you'd be better off using perl:

perl -0777 -ne 'print if s/foo\nbar/blah\nblup/'

Because the size is not limited in perl or GNU sed however beware that it may have an incidence on the performance of the system as it may end up using all the system memory if you don't have administratively set limits on per-process memory usage.

share|improve this answer
    
If you're going for historical implementations, you can't use semicolons as separators either. They are supported in recent POSIX versions and in OpenBSD and in BusyBox though. The lack of a ; before } does confuse OpenBSD. –  Gilles May 3 '13 at 23:04
    
@Gilles, not sure what implementation you had in mind, but that syntax works in Unix V7 (1979), just tested on a PDP11 emulator. By historical implementations, I meant the ones found for instance in the commercial Unices like AIX/Solaris/HPUX... descendants of Unix, or the one found in the Heirloom toolchest (port of OpenSolaris toolchest to Linux) –  Stephane Chazelas May 4 '13 at 7:29
add comment

why there is 1!H because to me 1h overwrites the pattern space and 1!H is of no use

No overwriting occurs as they are not executed on the same input line:

1h   # when input line number is 1, copy pattern space to hold space
1!H  # when input line number is not 1, append pattern space to hold space

That is necessary because according to info sed:

`H'
     Append a newline to the contents of the hold space, and then
     append the contents of the pattern space to that of the hold space.

So if you use just H to append all lines, there will be an extra newline before the first line:

bash-4.2$ seq 3 | sed -n 'H; ${g; p;}'

1
2
3
bash-4.2$ seq 3 | sed -n '1h; 1!H; ${g; p;}'
1
2
3
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.