该线程的动机是在此线程的链接中找到的算术命令这里在塞德.所以我想在 Sed 中进行向后算术。
数据
Mikael symptom
David symptom
hello symptom
命令应返回前两个条目。 Perl 中的后视是一种方法,但我想看看 Sed 是否可以做到这一点。
伪代码中的一种方法
- 匹配名称:
g/[A-Z]\w\w/
;中的单词is.words[2]('symptom')
向后看
- 匹配
symptom
;查找后面的名称。返回如果名称。
你能在 Sed 中写出这段伪代码吗?
答案1
sed '/^[[:upper:]][[:lower:]]\{1,\} symptom$/!d
H;x;/^\n/!q;s///;x;d'
这将查找以大写字符开头,后跟一个或多个小写字符的行,然后仅查找一个<空格>和字符串症状。如果当前行不匹配,则会将其d
删除,并且脚本会从顶部重新开始下一个输入行。
如果它做匹配它被复制到H
插入的行分隔符后面的旧空间\n
。第一次发生这种情况时,h
旧空间将是空的 - 因此主角将是一个\n
ewline。匹配行被H
ld 后,h
旧的和模式空间被 ex
改变。如果有!
不是\n
当时模式空间中的领先ewline 然后sed
q
uits 输入 - 突然停止读取更多输入(或在其脚本中执行任何更多命令 - 例如d
)根本不。但是,当存在前导\n
行被删除并且h
旧的和模式空间再次被x
改变并且模式空间被d
删除时。
结果是第一个遇到的行被保留,并且其表示的第一次出现标记将其从q
uitting 输入中保存下来,但是第二当它发生时结束处理。
但也许我误解了?我理解你的意思是你只想要文件中的前两个匹配项。
如果你只想要姓名如果症状$这很简单:
sed -n '/^[[:upper:]][[:lower:]]\{1,\} [^ ]*$/s/ symptom$//p'
在这里,我们只是验证我们确实正在寻找一个可能在尝试s///
替换之前匹配行 - 因为s///
替换是功能父地址。如果为真,我们会尝试修剪不需要的尾部,并且仅p
在成功时才进行打印 - 所以两个都在我们之前验证线头和尾部条件。
答案2
据我了解,您想要打印任何包含大写单词且紧随其后的单词的行symptom
。在这种情况下:
$ sed -rn '/\b[[:upper:]][[:lower:]]*[[:space:]]+symptom/p' data
Mikael symptom
David symptom
为了方便起见,我使用了\b
which来表示单词边界。这至少是 GNU sed 支持的。如果您的 sed 不支持,请告诉我。
怎么运行的:
基本形式是:
sed -n '/pattern/p' file
这仅打印匹配的行pattern
。在我们的例子中,该模式包括:
\b
这仅在单词边界匹配。
[[:upper:]][[:lower:]]*
这匹配一个大写字母后跟零个或多个小写字母。
请注意,在古代,这可能是这样写的
[A-Z][a-z]+
。由于 unicode,现在这是不可靠的。上面使用字符类upper
,lower
因此是 unicode 安全的。[[:space:]]+symptom
这与后跟单词 的一个或多个空格匹配
symptom
。
选择
假设您只想打印前面的名称symptom
:
$ sed -rn 's/\b([[:upper:]][[:lower:]]*)[[:space:]]+symptom.*/\1/p' data
Mikael
David
答案3
sed -n '/^[[:upper:]]\w* symptom/s/ .*//p'
打印以大写单词开头的行,symptom
然后删除除第一个单词之外的所有内容。