我刚刚经历过这个,但我无法理解。
sed -n '1h; 1!H; ${ g; s/foo\nbar/bla\nblub/ p }' file.
其中 cat 文件是:
foo
foo
bar
为什么会这样,1!H
因为对我来说1h
覆盖了模式空间并且1!H
没有用
但 sed oneliner 似乎工作正常。
答案1
看@manatwork 的回答的实际原因1h;1!H
,但我想添加一个可移植性说明。
标准且可移植的语法应该是:
sed -n '1h; 1!H; ${ g; s/foo\nbar/bla\
blub/p;}'
否则它在大多数实现中都无法工作sed
,例如传统的 Unix 实现。
这是\n
在命令的左侧可以理解的s
,但您必须在右侧使用反斜杠字符,后跟实际的换行符。您还需要命令 和;
之间有,并且 之前没有空格。s
}
p
您还可以将文件的内容存储在模式空间而不是保留空间中:
sed -n '
:1
$!{
N;b1
}
s/foo\nbar/blah\
blup/p'
但是对于模式和保存空间来说,大多数sed
实现只能处理小文件,因为大多数非 GNU 实现对这些文件的大小都有限制(POSIX 仅要求它们能够保存 8kiB 的数据)。
可移植的是,你最好使用perl
:
perl -0777 -ne 'print if s/foo\nbar/blah\nblup/'
perl
因为GNU中的大小不受限制sed
,但请注意,它可能会影响系统的性能,因为如果您没有对每个进程的内存使用进行管理设置限制,它最终可能会使用所有系统内存。
答案2
为什么有 1!H 因为对我来说 1h 会覆盖模式空间并且 1!H 没有用
不会发生覆盖,因为它们不是在同一输入行上执行:
1h # when input line number is 1, copy pattern space to hold space
1!H # when input line number is not 1, append pattern space to hold space
这是必要的,因为根据info sed
:
`H'
Append a newline to the contents of the hold space, and then
append the contents of the pattern space to that of the hold space.
因此,如果您仅使用H
附加所有行,则第一行之前会有一个额外的换行符:
bash-4.2$ seq 3 | sed -n 'H; ${g; p;}'
1
2
3
bash-4.2$ seq 3 | sed -n '1h; 1!H; ${g; p;}'
1
2
3