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.

Consider:

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.

share|improve this question
add comment

3 Answers

up vote 7 down vote accepted
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 \
lalala
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 \
lalala
: 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
   b
   : action
   a\
   lalala'

(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).

share|improve this answer
4  
Wow, sed subroutines. Cool –  glenn jackman Feb 28 at 17:29
    
Wow indeed, could you expand on those? They look really useful! –  terdon Feb 28 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 at 17:35
    
@terdon What could I? –  Hauke Laging Feb 28 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 at 17:42
show 4 more comments

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'
share|improve this answer
    
Can golf your perl a bit, using the "smart match" operator: perl -lnE 'say if $. ~~ @{[3,5]}' –  glenn jackman Feb 28 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 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 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 at 17:36
    
@AquariusPower also see updated answer. –  terdon Feb 28 at 17:38
show 3 more comments

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.

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.