使用 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
??
免责声明:
- 已经尝试过:
- use sed to insert a line after matching a block of text
- regex for appending text using sed
- ...还有其他...
- 但可能方式不正确...
- 意识到使用
awk
、perl
、python
或其他 tools/languages 会简单得多
- 但为什么不直接使用
sed
?!
使用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
我有一份报告(简单文本文件)需要更新(通过 bash)以供服务使用。
该报告由类别列表组成,每个类别都有一个项目列表,类似于以下示例:
vehicle:
car
moto
done
fruit:
banana
apple
done
tree:
pine
oak
done
更新的目的是在特定类别的最后一个项目之后添加新项目:
Add
orange
tofruit
afterapple
为此,我使用 sed
:
#!/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
??
免责声明:
- 已经尝试过:
- use sed to insert a line after matching a block of text
- regex for appending text using sed
- ...还有其他...
- 但可能方式不正确...
- 意识到使用
awk
、perl
、python
或其他 tools/languages 会简单得多- 但为什么不直接使用
sed
?!
- 但为什么不直接使用
使用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