gpt4 book ai didi

sed - 为什么 n 而不是 b 或 d 或什么都不改变 sed 在此脚本中的行为?

转载 作者:行者123 更新时间:2023-12-01 12:36:18 25 4
gpt4 key购买 nike

在为问题 How to extract content between two patterns in Unix 制定答案时,我在 sed 中遇到了一个我无法解释的行为——你能解释吗?

数据文件:data

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

目标是选择单词 fromwhere 之间的文本。

这是脚本的 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
    }

这些都适用于 BSD (Mac OS X) sed 和 GNU sed。最后一个脚本可以使用 b; } 并且它可以与 GNU sed 一起使用,但 BSD sed 拒绝它。

问题是 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 *and buttons = legsHello 在输出中?

$ 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 正确识别 where , 但 bd 都跳到下一个循环,就像 n 正常做的那样,但有一些不同。

鉴于两个独立的实现做同样的事情,我不得不假设这是故意的,但是......为什么?

最佳答案

总结

问题在于范围以及评估范围时模式空间中的内容。

sed 中的范围端点在计算范围时与模式空间的内容相匹配,而不是与原始输入行相匹配。因此,对于 sed -n '/start/,/end/{...}',重要的是命令开头的模式空间中的内容,而不是模式中的内容处理命令后或 n 导致读取更多行后的空格。

简单示例

p;n 与范围结合的问题可以用更简单的代码来说明。请注意,与 bd 不同,命令 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 读取的 where 实例永远不会结束一个范围。

进一步的论证

考虑 /1/,/END/ 范围,其中 END 从未出现在文件中:

$ seq 5 | sed -n 's/3/END/; /1/,/END/{p;n}'
1
END

尽管 END 从未出现在文件中,但它会在评估范围时出现在模式空间中。因此,它结束了范围。

作为另一个演示,让我们改变上述命令的顺序。下面,我们看到 END 虽然打印出来了,但并没有结束范围:

$ seq 5 | sed -n ' /1/,/END/{s/3/END/; p; n}'
1
END
5

这是因为 END 在评估范围时不在模式空间中。因此,sed 永远不会看到范围的尽头。

关于sed - 为什么 n 而不是 b 或 d 或什么都不改变 sed 在此脚本中的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29427151/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com