使用 sed 在带有文本块的 start maker 之后追加文本,直到结束标记

Use sed to append text after start maker with text block until end marker

我有一份报告(简单文本文件)需要更新(通过 bash)以供服务使用。

该报告由类别列表组成,每个类别都有一个项目列表,类似于以下示例:

vehicle:
car
moto
done

fruit:
banana
apple
done

tree:
pine
oak
done

更新的目的是在特定类别的最后一个项目之后添加新项目:

Add orange to fruit after apple

为此,我使用 sed:

创建了一个 test/debug 这个 procedure/update 的小示例脚本
#!/bin/bash

file=report.txt

cat > "$file" << EOT
vehicle:
car
moto
done

fruit:
banana
apple
done

tree:
pine
oak
done
EOT

category="fruit"
append="orange"

## only $category has $append - but at start:
#find_lhs="^$category:"
#replace_rhs="$category:\n$append"

## all categories have $append at end:
#find_lhs="([\S\s]*?)done"
#replace_rhs="$append\ndone"

# add $append at the end of $category - nothing happens:
find_lhs="^$category:([\S\s]*?)done"
replace_rhs="$category:\n$append\ndone"

sed -i -E "s/$find_lhs/$replace_rhs/g" "$file"

cat "$file"

问题:

什么是 missing/failing 与:

sed -i -E "s/^$category:([\S\s]*?)done/$category:\n\n$append\ndone/g" "$file"

生成如下报告内容:

vehicle:
car
moto
done

fruit:
banana
apple
orange #<-- inserted
done

tree:
pine
oak
done

??


免责声明:

使用sed

$ sed "/$category/,/done/{/done/s/^/$append\n/}" <<< "$file"
$ sed "/$category/{:a;/done/s/^/$append\n/;n;/^$/!ba}" file
$ sed -e "/$category/{:a;/done/i$append" -e 'n;/^$/!ba}' file

输出

vehicle:
car
moto
done

fruit:
banana
apple
orange
done

tree:
pine
oak
done

作为替代方案,这里有一个 gnu-awk 可以使用自定义 RS:

awk -v append='\norange' -v category='fruit:' -v RS='\ndone\n' '
{ORS=RT}  == category {[=10=] = [=10=] append} 1' file

vehicle:
car
moto
done

fruit:
banana
apple
orange
done

tree:
pine
oak
done
EOT

要将更改保存到同一个文件中,请使用:

awk -i inplace -v append='\norange' -v category='fruit:' -v RS='\ndone\n' '{ORS=RT}  == category {[=11=] = [=11=] append} 1' file

这可能适合您 (GNU sed):

sed -e '/fruit:/,/done/{/done/i\orange' -e '}' file

关注水果类别并在类别分隔符前插入 orange,即 done

N.B。解决方案分为两部分,因为 i 命令需要一个换行符或另一个命令集。

选择:

sed '/fruit:/,/done/!b;/done/i\orange' file