Bug 1867

Summary: sed: 'N' command followed by 'd' produces strange behaviour on subsequent lines
Product: Busybox Reporter: Stephen Bennett <spb>
Component: OtherAssignee: unassigned
Status: RESOLVED FIXED    
Severity: minor CC: busybox-cvs, pipping
Priority: P5    
Version: 1.16.x   
Target Milestone: ---   
Hardware: PC   
OS: Linux   
Host: Target:
Build:

Description Stephen Bennett 2010-05-30 15:13:19 UTC
$ echo -e "a\nb\nc\nd" | busybox sed -n '1{N;N;d};2p;3p;4p'
d
d
d

As far as I can tell, on line 1 an 'N' command will result in subsequent address matches for this line matching against both line 1 and line 2; two 'N' commands result in addresses for line 1, 2 and 3 all matching. This much seems reasonable, though I'm not sure what the standard says about it. GNU sed at least will match only line 3 in this situation (the above sed script prints only one "d").

However, following a 'd' command in the same block, this results in the next execution of the script, on input line 4, matching commands for lines 2, 3 and 4. This seems wrong.
Comment 1 Denys Vlasenko 2010-06-03 23:31:14 UTC
Fixed in git, thanks!

Patch:

                /* Are we continuing a previous multi-line match? */
                sed_cmd->in_match = sed_cmd->in_match
                        /* Or is no range necessary? */
                        || (!sed_cmd->beg_line && !sed_cmd->end_line
                                && !sed_cmd->beg_match && !sed_cmd->end_match)
                        /* Or did we match the start of a numerical range? */
-                       || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line <= linenum))
+                       || (sed_cmd->beg_line > 0
+                           && (sed_cmd->end_line || sed_cmd->end_match
+                                 /* note: even if end numeric and is < linenum too,
+                                  * GNU sed matches! We match too */
+                               ? (sed_cmd->beg_line <= linenum)    /* N,end */
+                               : (sed_cmd->beg_line == linenum)    /* N */
+                               )
+                           )
                        /* Or does this line match our begin address regex? */
                        || (beg_match(sed_cmd, pattern_space))
                        /* Or did we match last line of input? */