如何用sed实现跨行文本剪切追加的原地替换?
解决方案
可以用sed实现这个需求,核心是利用sed的**保持空间(Hold Space)**暂存需要移动的内容,结合多行模式处理完成剪切和追加操作。
具体sed命令
直接在bash脚本中使用以下命令即可批量处理文件:
sed -i -e ' /^find.* | while/,/^done/{ # 处理范围起始行(find开头的行) /^find.* | while/{ # 提取| while之前的内容 s/\(.*\) | while/\1/ # 存入保持空间 h # 清空当前模式空间,跳过后续处理 s/.*// b } # 处理中间以| while开头的行 /^| while/{ # 先移除行首的|,再提取| while之前的内容 s/^| \(.*\) | while/\1/ # 追加到保持空间 H # 清空当前模式空间,跳过后续处理 s/.*// b } # 处理范围结束行(done行) /^done/{ # 交换模式空间与保持空间(此时保持空间存的是所有待追加内容) x # 把保持空间里的换行替换为空格 s/\n/ /g # 给内容包裹< <() s/^/ < <(/ s/$/) # 把原done行追加回来(原done行在交换后的保持空间里) G } }' "$changeme"
命令解释
- 范围限定:
/^find.* | while/,/^done/{...}只处理从匹配find开头且包含| while的行,到匹配done的行这个区间内的内容。 - 起始行处理:提取该行
| while之前的部分,存入保持空间后清空当前行,最终输出为空(相当于删除原行的这部分内容,只保留后面的while...)。 - 中间行处理:先移除行首的
|,再提取| while之前的部分,追加到保持空间,同样清空当前行,只保留后面的内容。 - done行处理:将保持空间里的所有暂存内容拼接成一行,用
< <()包裹,再和原done行拼接,最终输出done < <(...)的形式。
示例验证
输入示例
find /var/log -name "*.log" | while read logfile | grep "error" "$logfile" | while read errline | echo "Error found: $errline" done
输出结果
while read logfile grep "error" "$logfile" | while read errline echo "Error found: $errline" done < <(find /var/log -name "*.log" grep "error" "$logfile" echo "Error found: $errline")
注意事项
- 若在macOS环境下使用,
sed -i需要添加空参数,即改为sed -i '' -e '...',否则会生成带后缀的备份文件。 - 确保目标文件中
find...| while和done的配对是正确的,避免跨区间的内容被错误处理。 - 如果区间内存在空白行或不符合匹配规则的行,需要根据实际情况调整正则表达式。
内容的提问来源于stack exchange,提问作者parricc
相关产品推荐
相关产品推荐

