为什么在这个脚本中,n而不是b或d或者什么都没有改变sed的行为?
在为这个问题寻找答案时,我在为什么在这个脚本中,n而不是b或d或者什么都没有改变sed的行为?,sed,Sed,在为这个问题寻找答案时,我在sed中遇到了一个我无法解释的行为-你能解释吗 数据文件:数据 Goodbye select * from dep where jkdsfj select * from sal where jkdsfj select elephants from abject poverty join flying tigers where abelone = shellfish; select mouse from toolset join a
sed
中遇到了一个我无法解释的行为-你能解释吗
数据文件:数据
Goodbye
select *
from dep
where jkdsfj
select *
from sal
where jkdsfj
select elephants
from abject poverty
join flying tigers
where abelone = shellfish;
select mouse
from toolset
join animals where tail = cord
and buttons = legs
Hello
目标是在单词from
和where
之间选择文本
以下是脚本的4种变体:
script.16
/from/,/where/ { s/.*from *//; s/ *where.*//; /^ *$/d; p; }
script.17
# Bust by final n; /from/,/where/ { s/.*from *//; s/ *where.*//; /^ *$/d; p; n; }
script.18
/from/,/where/ { s/.*from *//; s/ *where.*//; /^ *$/d; p; d; }
script.19
/from/,/where/ { s/.*from *//; s/ *where.*//; /^ *$/d; p; b }
sed
和GNUsed
一起使用。最后一个脚本可以使用b;}代码>和它将与GNUsed
一起工作,但BSDsed
拒绝它
问题在于script.17
的输出与其他3个不同,我无法理解为什么:
$ sed -n -f script.16 data
dep
sal
abject poverty
join flying tigers
toolset
join animals
$ sed -n -f script.17 data
dep
select *
abject poverty
toolset
and buttons = legs
Hello
$
为什么输出中有select*
和和按钮=legs
和Hello
$ sed -n -f script.18 data
dep
sal
abject poverty
join flying tigers
toolset
join animals
$ sed -n -f script.19 data
dep
sal
abject poverty
join flying tigers
toolset
join animals
$
为什么使用n
会像这样改变sed
的行为?从我尝试的诊断“打印”的一些变体来看,n
似乎阻止了sed
在正确地看到的位置时识别,但是b
和d
都跳到下一个周期,就像n
正常工作一样,但有些不同
鉴于两个独立的实现做相同的事情,我不得不假设这是有意为之,但是……为什么?Summary
问题在于范围以及评估范围时模式空间中的内容
sed中的范围端点在计算范围时与模式空间的内容相匹配,而不是与原始输入行相匹配。因此,对于sed-n'/start/,/end/{…}'
,重要的是命令开始时模式空间中的内容,而不是在处理命令或n
导致读取更多行之后模式空间中的内容
简单例子
p问题;n
结合一个范围可以用更简单的代码来说明。请注意,与b
和d
不同,命令n
以行形式读取。因此,sed-n'p;n'
每隔一行打印一次。例如:
$ seq 5 | sed -n 'p;n'
1
3
5
现在,观察p;n
与一个范围结合使用:
$ seq 5 | sed -n '/1/,/3/{p;n;}'
1
3
以上工作如预期。然而,以下几点令人惊讶:
$ seq 5 | sed -n '/1/,/2/{p;n;}'
1
3
5
包含2
的行由n
命令读入,然后立即丢弃。计算范围/1/,/2/
时,包含2
的行不会出现在模式空间中。因此,sed
永远看不到/1/、/2/
的结束,它一直认为它在范围之内
剧本17
现在,让我们考虑一下你的脚本17,稍加修改:
sed -n '/from/,/where/ { s/.*from */BEGIN/; s/ *where.*/END/; /^ *$/d; p; n; }' data
BEGINdep
select *
END
BEGINabject poverty
END
BEGINtoolset
and buttons = legs
Hello
这里,我们看到范围/from/,/where/
从from
的出现一直延续到下一次where
在计算范围时出现在命令开始时的模式缓冲区中。由n
读取的实例,其中
从不结束一个范围
进一步的论证
考虑范围/1/,/END/
,其中END
never出现在文件中:
$ seq 5 | sed -n 's/3/END/; /1/,/END/{p;n}'
1
END
即使END
nevers出现在文件中,它也会在计算范围时出现在模式空间中。因此,它结束了这个范围
作为另一个演示,让我们更改上述命令的顺序。下面,我们看到,END
虽然被打印出来,但并没有结束该范围:
$ seq 5 | sed -n ' /1/,/END/{s/3/END/; p; n}'
1
END
5
这是因为计算范围时,END
不在模式空间中。因此,sed
永远看不到范围的尽头