假设有一个文件“abc.txt”包含一个段落/行:
Hello, how are you doing sir?
when are you going to arrive at the SBAHN platform to catch the train?
如何提取文件中从“how”到“catch”的所有字符?
答案1
如果您有支持 PCRE 的版本,grep
您可以使用以下命令来执行您想要的操作:
$ grep -Pzo 'how.*\n.*catch' file
how are you doing sir?
when are you going to arrive at the SBAHN platform to catch
开关:
-P
- 启用PCRE - Perl 兼容的正则表达式-z
- 输出零字节(ASCII NUL 字符),而不是通常跟在文件名后面的字符。例如,grep -lZ
在每个文件名后输出一个零字节,而不是通常的换行符。即使文件名包含换行符等不常见字符,此选项也会使输出明确无误。此选项可与find -print0, perl -0
、sort -z
、 和等命令一起使用xargs -0
来处理任意文件名,甚至包含换行符的文件名。-o
- 仅打印匹配行的匹配(非空)部分,每个此类部分位于单独的输出行上。
答案2
适合这项工作的工具是pcregrep
pcregrep -oM "how(.|\n)*catch" SPEC
pcregrep
:具有与 Perl 兼容的正则表达式的 grep。-o
:仅显示与模式匹配的行的部分-M
:允许模式匹配多行(.|\n)*
:匹配任何字符或换行符零次或多次
如果您想要非贪婪的版本,请?
在之后添加*
:
pcregrep -oM "how(.|\n)*?catch" SPEC
答案3
使用sed
这个答案假设你有一个sed
可以处理长队的良好品质。假设您的文本位于名为的文件中file
:
$ tr '\n' '\001' <file | sed -n -r 's/.*(how.*catch).*/\1\n/p' | tr '\001' '\n'
how are you doing sir?
when are you going to arrive at the SBAHN platform to catch
解释:
tr '\n' '\001' <file
这将从文件中读取
file
并用八进制 001 字符替换所有换行符。这具有将输入转换为单行的效果。sed -n -r 's/.*(how.*catch).*/\1\n/p'
现在输入是单行,
sed
可以轻松处理此任务。上面的替换命令捕获从“how”到“catch”的所有文本并将其打印到标准输出由于使用了该
-n
选项,除非正则表达式匹配,否则不会打印任何内容。因此,如果输入没有how.*catch
序列,则不会打印任何内容。tr '\001' '\n'
这会将八进制 001 字符转换回换行符。
八进制 001 可以替换为 (a) 您确定不在输入文件中并且 (b) 您sed
可以正确处理的任何字符。
使用awk
$ awk '/how/{f=1;sub(/.*how/,"how")} /catch/{f=0;sub(/catch.*/,"catch");print} f' file
how are you doing sir?
when are you going to arrive at the SBAHN platform to catch
解释:
/how/{f=1;sub(/.*how/,"how")}
如果该行包含单词“how”,则会删除“how”之前的所有文本并将标志变量设置
f
为 1/catch/{f=0;sub(/catch.*/,"catch");print}
如果该行包含单词“catch”,则会删除“catch”之后的所有文本,将标志变量设置
f
为 0 并打印修改后的行。f
如果标志为 1,这个有点神秘的 awk 命令将导致打印该行。如果
f==0
,则不打印任何内容。
答案4
sed
如果文本不是文件的一部分,该示例将失败,然后您将获得完整的文件,而不是什么也没有。
使用 grep 代替 sed:
tr '\n' '\001' < file | grep -o -E 'how.*catch' | tr '\001' '\n'
贪婪和非贪婪匹配也是一个问题,因此如果“catch”位于第 2 行,另一个“catch”位于第 5 行,则您需要非贪婪匹配。
请阅读此处如何实现这一点,这在很大程度上取决于版本grep
: