2

I have

#!/usr/bin/bash
search="ldo_vrf18 {"
replace="$search"'                      compatible = "regulator-fixed";
                        regulator-name = "vrf18";
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                        regulator-enable-ramp-delay = <120>;'
sed -i "s/$search/$replace/g" output.file

The result is

sed: -e expression #1, char 62: unterminated `s' command

I suspect some values arent being escape in replace. Is there a way to escape them? I have tried sed -i 's/'"$search"'/'"$replace"'/g' output.file with the same result

0

1 Answer 1

2

The problem is with the newlines in the $replace variable, which are interpreted by sed as end of command.

In order to solve that in GNU sed, you'll need to replace the new lines in your $replace variable with a literal \n:

replace=${replace//$'\n'/\\n}

Note: The solution above will not work in all sed implementations, as it's an extended feature in some versions (for instance, in GNU sed). According to the POSIX standards:

Each embedded <newline> in the text shall be preceded by a backslash. Other backslashes in text shall be removed+, and the following character shall be treated literally.

So on POSIX sed, the literal \n will lose it's meaning as a newline and be treated just as a literal n character. For a portable solution that would work on all sed implementations, precede the actual newlines with a backslash:

replace=${replace//$'\n'/\\$'\n'}

+ Except for backslash followed by a digit:

The characters "\n", where n is a digit, shall be replaced by the text matched by the corresponding backreference expression. [...] For each other backslash ( '\' ) encountered, the following character shall lose its special meaning (if any).

8
  • 2
    And note that inserting newlines with \n using the s command is an extended feature that not all sed implementations have. To do it portably, escape each literal newline with a backslash.
    – Kusalananda
    Nov 6, 2023 at 17:59
  • 1
    @Kusalananda oh, I see what you mean: replace=${replace//$'\n'/\\$'\n'} ?
    – aviro
    Nov 6, 2023 at 18:15
  • Standard sed (as found on e.g. some BSD systems) does not understand that \n means a literal newline when it occurs in the replacement text and will insert an n instead. To be portable, you would have to ensure that each literal newline in $replace is escaped. If you use replace=${replace//$'\n'/\\$'\n'} in bash, that would do it.
    – Kusalananda
    Nov 6, 2023 at 18:15
  • Yes, exactly what I meant.
    – Kusalananda
    Nov 6, 2023 at 18:16
  • 1
    @Kusalananda just for the sake of completeness and after a further research, it's not strictly a bug. From POSIX: The meaning of a '\' immediately followed by any character other than '&', '\', a digit, or the delimiter character used for this command, is unspecified. See also this bug report.
    – aviro
    Nov 7, 2023 at 16:21

Not the answer you're looking for? Browse other questions tagged .