Sed: delete lines without pattern except first

Viewed 880

How to delete lines that do not match the pattern except the first line?

To delete lines except first i use sed '1!d'

To delete lines that do not match patter i use sed '/pattern/!d'

How can i use both of conditions? Things like sed '1!/pattern/!d' doesn't work, says unknown command: '/'

As example (if pattern="rcu") from input

  PID  PPID PRI  NI    VSZ   RSS STAT     TIME CMD
    1     0  19   0  33664  4832 Ss   00:00:07 /sbin/init splash
    2     0  19   0      0     0 S    00:00:00 [kthreadd]
    3     2  39 -20      0     0 I<   00:00:00 [rcu_gp]
    4     2  39 -20      0     0 I<   00:00:00 [rcu_par_gp]
    8     2  39 -20      0     0 I<   00:00:00 [mm_percpu_wq]
    9     2  19   0      0     0 S    00:00:04 [ksoftirqd/0]

get

  PID  PPID PRI  NI    VSZ   RSS STAT     TIME CMD
    3     2  39 -20      0     0 I<   00:00:00 [rcu_gp]
    4     2  39 -20      0     0 I<   00:00:00 [rcu_par_gp]

Thanks

4 Answers

Output first line and all lines which contain rcu:

sed -n '1p; /rcu/p' file

You could also make a script that reads the file and “extracts” first line that don’t match the pattern (to another temporary file or to the string), make other operations like deleting lines that you want to be deleted and paste that line back in the same place in the file.

As you have tagged awk

awk '{if ($0~/rcu/) print}' 

Demo :

$ cat file1.txt
  PID  PPID PRI  NI    VSZ   RSS STAT     TIME CMD
    1     0  19   0  33664  4832 Ss   00:00:07 /sbin/init splash
    2     0  19   0      0     0 S    00:00:00 [kthreadd]
    3     2  39 -20      0     0 I<   00:00:00 [rcu_gp]
    4     2  39 -20      0     0 I<   00:00:00 [rcu_par_gp]
    8     2  39 -20      0     0 I<   00:00:00 [mm_percpu_wq]
    9     2  19   0      0     0 S    00:00:04 [ksoftirqd/0]
$ awk '{if ($0~/rcu/) print}' file1.txt
    3     2  39 -20      0     0 I<   00:00:00 [rcu_gp]
    4     2  39 -20      0     0 I<   00:00:00 [rcu_par_gp]
$

If when you say except the first if you mean except the first line of the input even if it doesn't match the regexp then this is what you want:

$ awk '/rcu/ || NR==1' file
  PID  PPID PRI  NI    VSZ   RSS STAT     TIME CMD
    3     2  39 -20      0     0 I<   00:00:00 [rcu_gp]
    4     2  39 -20      0     0 I<   00:00:00 [rcu_par_gp]

or if you mean except the first line that doesn't match the regexp then this is what you want:

$ awk '/rcu/ || !c++' file
  PID  PPID PRI  NI    VSZ   RSS STAT     TIME CMD
    3     2  39 -20      0     0 I<   00:00:00 [rcu_gp]
    4     2  39 -20      0     0 I<   00:00:00 [rcu_par_gp]
Related