使用 sed 修改文档特定部分中的一行

Modify a line in a particular section of a document with sed

我想使用 sed 修改 Debian control file 来更改特定软件包的依赖项。

该文件包含多个包的元数据,其中条目如下所示:

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.

我想找到匹配 Package: linux-image-generic 的行,然后修改下面匹配 Depends: 的行,例如通过执行 s/linux-image-/linux-image-unsigned-/.

这是我修改 Depends: 行的解决方案,但仅限于 linux-image-generic 部分。

此解决方案适用于 GNU sed,但稍作修改使其适用于 BSD sed,如下所述。

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

它以 range address 开头,匹配从包元数据的开头到包块之后的空行。

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

然后它使用 {} 在 这个范围内应用命令

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

此处的第一部分 /^Depends:/ 是一个 regular expression address,仅选择以 Depends:.

开头的行

最后,s command 对所选行执行替换。


BSD sed(在 macOS 等上)有一个额外的函数列表语法规则 { ... }:

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

我们需要在}之前插入一个换行符,例如在Bash中使用$'\n' ANSI-C string:

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

顺便说一句,找到此解决方案的途径是研究 sed 对具有类似语法的其他文件格式进行操作的命令,例如 INI files.

您找到的sed解决方案是完美的。为了完整起见,使用 GNU awk 而不是 sed:

awk -v RS= -v ORS='\n\n' '/^Package: linux-image-generic/ {
  [=10=] = gensub(/(\nDepends:[^\n]*linux-image-)/,"&unsigned-",1)} 1' file

如果输入的记录分隔符(RS)为空字符串,则记录由空行分隔。因此,文件的每个部分都是一条记录。 gensub 进行替换。

这可能适合您 (GNU sed):

sed '/Package: linux-image-generic/{:a;n;/Depends:/!ba;s/linux-image-/&unsigned-/}' file

查找包含 Package: linux-image-generic 的行然后继续阅读直到包含 Depends: 的行并将 linux-image- 替换为 linux-image-unsigned-.

N.B。这假定包节包含 Depends:,如果不包含,则:

sed -E '/Package:/{h;:a;n;/Package:/{h;ba};/Depends/!ba;G
       s/(linux-image-)(.*)\n.*Package: linux-image-generic/unsigned-/}' file