regex - sed 正则表达式:组重复选项?
问题描述
我有一个包含几行的文本输入。每个组由一个空行 (\n\n) 分隔。我正在使用 sed 进行处理,但我对替代方案持开放态度。
我正在使用这个结构来一次处理所有的行:
# if the first line copy the pattern to the hold buffer
1h
# if not the first line then append the pattern to the hold buffer
1!H
# if the last line then ...
$ {
# copy from the hold to the pattern buffer
g
... here are my regex lines.
# print
p
}
我对每个组的目标输出是每一行,但第一行以第一行的内容为前缀,以空格分隔。
由于我当前的输入只有 2、3 和 6 行组,因此我将其“硬编码”如下:
2行:
s/\n\n\([^\n]\+\)\n\([^\n]\+\)\n\n/\n\n\1 \2\n\n/g
3行:
s/\n\n\([^\n]\+\)\n\([^\n]\+\)\n\([^\n]\+\)\n\n/\n\n\1 \2\n\n\1 \3\n\n/g
6行:
s/\n\n\([^\n]\+\)\n\([^\n]\+\)\n\([^\n]\+\)\n\([^\n]\+\)\n\([^\n]\+\)\n\([^\n]\+\)\n\n/\n\n\1 \2\n\n\1 \3\n\n\1 \4\n\n\1 \5\n\n\1 \6\n\n/g
(我有两次这些正则表达式行,因为可能需要一组的结尾 \n\n 并且不能用于匹配下一组的开头)
我正在寻找一种适用于从 2 到 n 行的任何大小的组的通用方法。有人对此有任何想法吗?
更新:因为@Benjamin W. 要求样本输入/输出:
我在这里要解决的真正问题是为温度记录守护进程动态生成一个 csv 标题行,该守护进程的数据来自sensors -u
. (因为当我的笔记本电脑重启时,输出的顺序似乎发生了变化)
使用 sed 很容易从原始程序输出中得到:
jc42-i2c-0-1a SMBus I801 adapter at f040
temp1
asus-isa-0000 ISA adapter
cpu_fan
temp1
acpitz-acpi-0 ACPI interface
temp1
jc42-i2c-0-18 SMBus I801 adapter at f040
temp1
coretemp-isa-0000 ISA adapter
Package id 0
Core 0
Core 1
Core 2
Core 3
我上面提到的 3 sed 正则表达式替换行允许我将其转换为:
jc42-i2c-0-1a SMBus I801 adapter at f040 temp1
asus-isa-0000 ISA adapter cpu_fan
asus-isa-0000 ISA adapter temp1
acpitz-acpi-0 ACPI interface temp1
jc42-i2c-0-18 SMBus I801 adapter at f040 temp1
coretemp-isa-0000 ISA adapter Package id 0
coretemp-isa-0000 ISA adapter Core 0
coretemp-isa-0000 ISA adapter Core 1
coretemp-isa-0000 ISA adapter Core 2
coretemp-isa-0000 ISA adapter Core 3
但这当然只适用于具有 1、2 或 5 个值的适配器的机器。
更新 2019-02-11:
因此,在我得到两个建议通用解决方案的答案后,我再次查看了这个问题并大大简化了我的整个温度记录脚本:
echo -n "timestamp"
sensors -u | # -u gives Raw output, suitable for easier post-processing
grep --invert-match ' ' | # remove all lines containing values, leaving only headers
sed -n 'H; ${x; s/\nAdapter: / /g; p}' | # join headers spanning two lines together. For syntax see: https://unix.stackexchange.com/questions/163428/replace-a-string-containing-newline-characters & http://www.grymoire.com/Unix/Sed.html#uh-55
sed 'N;/\n$/d;s/\(.*\)\n\(.*\):/\1 \2\n\1/;P;$d;D' | # join the headers header with each sub-header, see: https://stackoverflow.com/questions/54576948/sed-regex-group-repeat-option
tr '\n' ';' | sed 's/.$//' # join finished headers together in a single line sepearted by ; & remove the trailing ;
echo ""
while true
do
ts=`date +"%Y-%m-%d %H:%M:%S"`
echo -n "$ts;"
sensors -u | grep --invert-match '_max\|_crit\|_min' | # remove min max crit values which represent config, not state.
grep '\.' | # remove all non value lines left (headers & empty lines seperating blocks
sed 's/ .*: //g' | # remove value names, leaving only the values themselfs
sed 's/\.000//g' | # remove empty decimals
tr '\n' ';' | sed 's/.$//' # join finished values together in a single line sepearted by ; & remove the trailing ;
sleep 1
echo ""
done
解决方案
这可能对您有用(GNU sed):
sed 'N;/\n$/d;s/\(.*\)\n\(.*\)/\1 \2\n\1/;P;$d;D' file
将下一行追加到当前行。
如果附加的行是空的,即\n$
表示一个空行,则完全删除模式空间并恢复,就好像没有行被消耗掉一样。
否则,模式空间中的两行都是非空的,因此将两行转换为一个,然后将第一行附加到结果中。
打印模式空间中的第一行。
如果它是文件的最后一行,则删除模式空间。
删除模式空间中的第一行。
重复。
NBD
删除模式空间中的第一行,如果模式空间不为空,则不会隐式将模式空间替换为下一行。
推荐阅读
- javascript - 如何在 Typescript 中重新排列不同类型的关联数组?
- python - 在 Postgresql 中插入特殊字符的问题
- python - 对 numpy 数组中的行进行平均时 Numba 出现 TypeError
- file - FFMPEG 从文本文件中读取输入并同时从文件中过滤复杂
- laravel - 如何在 Laravel 中不接受来自 post 请求的查询参数
- docker - 具有多个参数时的 docker 指令格式
- ffmpeg - FFmpeg 使用自定义“af”s 向下复用多个轨道
- typescript - 从输入项的类型参数推断输出数组类型
- ios - xcode - 产品 - 存档 - 分发应用程序显示错误:存档不包含任何无法签名的内容
- html - 为什么我的 flex 列中的最后一个元素没有对齐?