我希望使用GNU sed来替换\ n当\ n每行(从管道传入)以指定模式开头但我的sed命令似乎不起作用:
$ cat mpv_all.log | sed -z '/^AV:/s/\n/\r/g'
你能帮我么 ?
问题是-z
导致整个文件立即被读入。因此,如果文件以^AV:
开头,则AV:
仅匹配。你可能想在每一行上匹配AV:
。在这种情况下,请尝试:
sed -Ez ':a; s/((^|[\n\r])AV:[^\n\r]*)\n/\1\r/g ;ta' mpv_all.log
这个怎么运作:
-E
启用扩展正则表达式。:a
定义标签a
。s/((^|[\n\r])AV:[^\n\r]*)\n/\1\r/g
用\n
取代\r
,以AV:
开头。ta
告诉sed如果先前的替换命令导致任何更改,则返回标签a
。这是必要的,因为模式可能重叠,而g
命令的s
修饰符不会重叠。如果awk也是一个选项:
awk '{ORS=/^AV:/?"\r":"\n"}1' file
ORS
是输出记录分隔符;默认设置为\n
。但是在上面的脚本中,它的值会动态变为\r
或\n
,具体取决于输入行是否匹配/^AV:/
(即以AV:
开头)。
ORS=/^AV:/?"\r":"\n"
是一个简写
if (/^AV:/)
ORS="\r"
else
ORS="\n"
脚本末尾的1
代表{print}
。
只是为了给出一个perl实现:
$ perl -p -e '$| = 1;s/\n/\r/g if $_ =~ /^AV:/;s/Saving state/\nSaving state/;' mpv_all.log
-p
在文件的每一行循环-e
在引号中运行perl命令$| = 1;
Perl在每一行刷新缓冲区s/\n/\r/g if $_ =~ /^AV:/;
开头的每一行都用qazxsw poi取代qazxsw poi\n
将\r
线放在下面一行,以免覆盖AV:
的最后一行