Friday, May 27, 2022

[SOLVED] Modify a line in a particular section of a document with sed

Issue

I'd like to use sed to modify a Debian control file to change the dependencies of a particular package.

The file contains metadata for several packages, where entry looks like this:

Package: linux-image-generic
Architecture: i386 amd64 armhf arm64 powerpc ppc64el s390x
Section: kernel
Provides: ${dkms:zfs-modules} ${dkms:virtualbox-guest-modules} ${dkms:wireguard-linux-compat-modules}
Depends: ${misc:Depends}, linux-image-${kernel-abi-version}-generic, linux-modules-extra-${kernel-abi-version}-generic [i386 amd64 arm64 powerpc ppc64el s390x], linux-firmware, intel-microcode [amd64 i386], amd64-microcode [amd64 i386]
Recommends: thermald [i386 amd64]
Description: Generic Linux kernel image
 This package will always depend on the latest generic kernel image
 available.

Package: linux-tools-generic
Architecture: i386 amd64 armhf arm64 powerpc ppc64el s390x
Section: kernel
Provides: linux-tools
Depends: ${misc:Depends}, linux-tools-${kernel-abi-version}-generic
Description: Generic Linux kernel tools
 This package will always depend on the latest generic kernel tools
 available.

I would like to find the line that matches Package: linux-image-generic, then modify the following line that matches Depends:, for instance by performing s/linux-image-/linux-image-unsigned-/.


Solution

Here's my solution that modifies the Depends: line, but only within the linux-image-generic section.

This solution for GNU sed, but a slight modification makes it work for BSD sed, noted below.

sed '/^Package: linux-image-generic$/,/^$/{/^Depends:/ s/linux-image-/linux-image-unsigned-/}' debian/control

It starts with a range address that matches from the beginning of the package metadata up to the blank line after the package block.

/^Package: linux-image-generic$/,/^$/

Then it uses a {} to apply a command within this range:

/^Depends:/ s/linux-image-/linux-image-unsigned-/

The first part here, /^Depends:/, is a regular expression address that selects only the line(s) that begin with Depends:.

Lastly, the s command performs the substitution on the selected line.


BSD sed (on macOS, etc.) has an additional syntactic rule for function lists { ... }:

The terminating “}” must be preceded by a newline, and may also be preceded by white space.

We need to insert a newline before the }, for example by using the $'\n' ANSI-C string in Bash:

sed '/^Package: linux-image-generic$/,/^$/{/^Depends:/ s/linux-image-/linux-image-unsigned-/'$'\n''}' debian/control

As an aside, the path to finding this solution was to research sed commands that operate on other file formats with similar syntaxes, like INI files.



Answered By - rgov
Answer Checked By - Senaida (WPSolving Volunteer)