echo -e "a\nb\nc\nd\ne\nf\ng\nh" | sed '3,5a test'

This will match lines 3, 4 and 5.

But I am trying to match only lines 3 and 5 (not 4). And append 'test' after them.

echo ... | sed -e '3a test' -e '5a test'

If the operation is more complex than in this case then you can use a structure like this:

sed 'b pattern; : action; a \
b end; : pattern; 3b action; 5b action; : end'

I.e. you put all commands you need between b pattern; and b end;.

And you add all your patterns (line numbers or whatever) after : pattern;.

What happens is this:

  1. The first command jumps over the action part (maybe it's easier to read if the patterns are at the beginning and b end; directly before the action part).

  2. If a pattern matches then the execution jumps to the action part. After the action part execution jumps to the end.

I try to tidy this up:

sed '3b action; 5b action; b end; : action; a \
: end'

In a single line would be like:

sed "3b idAction; 5b idAction; b; : idAction; a test"

Portably, you need to write it:

sed '
   3b action
   5b action
   : action

(b without label branches to the end, so you don't need an explicit end label, ; is valid a character in a label in standard sed implementations).

  • 4
    Wow, sed subroutines. Cool – glenn jackman Feb 28 '14 at 17:29
  • Wow indeed, could you expand on those? They look really useful! – terdon Feb 28 '14 at 17:32
  • the one with 'pattern' and 'action' seems very good as I do not need to repeat 'test' (or 'lalala'), got to still better understand it tho thx! :) – Aquarius Power Feb 28 '14 at 17:35
  • @terdon What could I? – Hauke Laging Feb 28 '14 at 17:39
  • I meant that the second one looks great but is hard to understand and if you have the time, I'd appreciate an explanation. – terdon Feb 28 '14 at 17:42

With sed (see @HaukeLaging's answer)

With awk:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | awk 'NR==3 || NR==5{$0=$0"\ntest"}1;'

With perl:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | perl -pe '$_ .="test\n" if $. == 3 || $. == 5'
  • Can golf your perl a bit, using the "smart match" operator: perl -lnE 'say if $. ~~ @{[3,5]}' – glenn jackman Feb 28 '14 at 17:28
  • @glennjackman ah, yes indeed, thanks. I have to admit that I'm a bit wary of ~~, don't understand it as well as I should. Also, both say and ~~ need perl v >= 5.10 right? – terdon Feb 28 '14 at 17:29
  • I need to append 'test' after that lines, I see now it would have been better to have clarified that from the beginning. I just edited the OP. – Aquarius Power Feb 28 '14 at 17:32
  • @AquariusPower, perl -pE 'say "test" if $. ~~ @{[4,6]}' -- this prepends the line: perl's -p does an implicit print at the end of the given program. – glenn jackman Feb 28 '14 at 17:36
  • @AquariusPower also see updated answer. – terdon Feb 28 '14 at 17:38

As @HaukeLaging aleady said, this command does what you want:

sed -e'3a test' -e'5a test'

Now, this can become rather cumbersome to type if you want to match, e.g., 20 lines.

In these cases, assuming your shell supports brace expansion, you can use this command instead:

sed -e{3,5}'a test'

(Note that the braces and the comma must remain unquoted.)

As a result, the shell will pass the arguments to -e3a test and -e5a test to sed, which is exactly what the first command does.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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