sedbusybox

BusyBox Linux sed does not replace first line when I run this command


I have a script that needs to replace the first line that contains a specific phrase. It should not replace any other lines of text.

Using this:

sed -i '1,/old/ s/.*old.*/new/' temp 

This correctly replaces the entire line containing 'old' with 'new'. But I noticed that if 'old' is on the first line, this does not work. I tried using 0 instead of 1 and it does not work at all, no replacements.

Please let me know if anyone has another way to do this that will also work on the first line.

The contents of the temp file are:

line 1 has 'old value' here.
line 2 has 'old value' here.

This is on an embedded device that uses sed as part of BusyBox.

Versions are:

BusyBox v1.29.3 (2022-11-02 08:55:42 PDT) multi-call binary.
$ sed --version
This is not GNU sed version 4.0
$

The sed C source from BusyBox is posted at: https://github.com/brgl/busybox/blob/master/editors/sed.c


Solution

  • By "this does not work", I assume you mean more lines are replaced than desired.


    You are using the substitute command inside a range test.

    The form is: address1 , address2 command

    Addresses are generally specified as an absolute number, $ (final line of file), or a regular expression.

    The significant point is that the test for address2 does not happen until the line after the line that matches address1.

    In your command:

    This means /old/ is not checked until line 2.

    GNU sed has a non-standard extension where address1 can be 0, which is taken to mean that the range begins at the start of the file (a notional line zero) and testing for address2 begins from the first line. It seems busybox sed does not support that extension.

    You could rewrite your script as, for example:

    sed -i '
        /.*old.*/!b
        s//new/
    :loop
        n
        bloop
    ' temp
    

    Specifying an empty regex to s/// reuses the last RE used in the last command applied.