sed 相当于“grep -o”的是什么?

Jos*_*hro 4 grep sed regular-expression

我希望 sed 相当于:\n .\xc2\xa0\nI\xc2\xa0 假设,希望对输出进行进一步的处理。\xc2\xa0\n这一步可能只是某些事情的第一部分\n通过添加更长的 sed 表达式将更加详细。grep -Eo 'regex';\xc2\xa0s\xe2\x80\xa6

\n

更清楚地说,我希望能够隔离每个字符串\n匹配\xc2\xa0输入流中给定的正则表达式。\xc2\xa0\n为了概念验证的目的,\n每个这样的字符串应该输出为\ xc2\xa0 没有\xc2\xa0context\n 的单独行(即,\xc2\xa0no\xc2\xa0 周围的文本来自\xc2\xa0input)。\xc2\xa0\n因此\xc2\xa0an\xc2\xa0input 行有多个 (非重叠)匹配\n应导致多个输出行;\n没有匹配的输入行应导致无\xc2\xa0输出。

\n

例子:

\n

正则表达式: [a-zA-Z]{3}[0-9]{4} \xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\n(即\xc2\xa0后面跟着三个字母四位数字)

\n

输入:

\n
FGH1234 and CAS4057\nMAX2345\n
Run Code Online (Sandbox Code Playgroud)\n

输出:

\n
FGH1234\nCAS4057\nMAX2345\n
Run Code Online (Sandbox Code Playgroud)\n

row*_*oat 10

更新以修复零长度正则表达式匹配的行为:

sed 't match;s/REGEX/\n&\n/g;D;:match;/^\n/!P;s/\n//;D' file
Run Code Online (Sandbox Code Playgroud)

全局替换匹配<newline><matched part><newline>. 然后通过创建循环P;s/\n//;D来打印它们t match,依此类推,直到打印完所有匹配的部分。/^\n/!P使用而不是 justP以便只打印非空匹配(就像 GNUgrep -o那样)。

使用的类似方法awk可以是:

regex='REGEX' awk 'BEGIN {FS="\n"}
  gsub(ENVIRON["regex"], FS "&" FS) {for (i=2;i<NF;i+=2) if ($i!="") print $i}
' file
Run Code Online (Sandbox Code Playgroud)

原始尝试:请注意,当给定与空字符串(例如.*)匹配的正则表达式时,这些命令的行为会很糟糕 - 空行将在无限循环中打印。

通过一次调用sed

sed '
t match
s/[[:alpha:]]\{3\}[[:digit:]]\{4\}/\
&\
/;D;:match
P;D' file
Run Code Online (Sandbox Code Playgroud)

使用POSIXsed语法:regex 是基本正则表达式,\在 的替换字符串中使用转义换行符s///,并且使用换行符而不是;在分支标签之后。某些版本sed(例如 GNU sed)可以在一行上接受所有脚本:

sed 't match;s/[[:alpha:]]\{3\}[[:digit:]]\{4\}/\n&\n/;D;:match;P;D' file
Run Code Online (Sandbox Code Playgroud)

替换通过在匹配部分之前和之后添加换行符来隔离第一个匹配项。t match仅在成功替换后才会遵循脚本开头的条件分支。:match是打印匹配部分的地方。D使用以便从模式空间中删除包含匹配的行,并将剩余部分用作下一个循环的输入,从而允许找到更多匹配。


G-M*_*ca' 7

这与rowboat\xe2\x80\x99s 答案非常相似(但独立开发),\n并且可能有稍微更详细的解释。

\n

使用 GNU sed:

\n
sed -En \'t dummy; : dummy; s/[a-zA-Z]{3}[0-9]{4}/&\\n/; T; s/.*([a-zA-Z]{3}[0-9]{4}\\n)/\\1/; P; D\'\n
Run Code Online (Sandbox Code Playgroud)\n

解释:

\n
    \n
  • -E\xe2\x80\x83\xe2\x80\x83\n使用扩展正则表达式(ERE)。\xc2\xa0\n如果没有这个,我们就不得不说\\{3\\}and\xc2\xa0 \\{4\\}

    \n
  • \n
  • \xe2\x80\x82 n\xe2\x80\x83\xe2\x80\x83\nDon\xe2\x80\x99t 自动打印任何内容;只打印我们所说的打印内容。\xc2\xa0\n这个\xc2\xa0是\xc2\xa0理想的,因为,像 一样grep,我们不想打印\n对于不\xe2\x80\x99t包含与正则表达式匹配的字符串的输入行。

    \n
  • \n
  • t dummy; : dummy\xe2\x80\x83\n跳转到紧随其后的 (\xe2\x80\x9c dummy\xe2\x80\x9d) 标签。\xc2\xa0\n这个\xc2\xa0 是一个\xc2\xa0 条件跳转,因此它可能或可能不会发生。\xc2\xa0\n但是\xe2\x80\x99并不重要,\n因为\xe2\x80\x99在跳转命令和\xc2\xa0the\xc2\xa0标签之间没有任何内容。

    \n

    这看起来像一个无操作,而且确实是这样,除了它清除 sed\xe2\x80\x99s 内存\n是否存在成功的替代命令。

    \n
  • \n
  • s/[a-zA-Z]{3}[0-9]{4}/&\\n/\xe2\x80\x83\n查找 OP\xe2\x80\x99s 正则表达式。\xc2\xa0\n如果\xc2\xa0找到,则将其替换为自身加上\xc2\xa0换行符(即\xc2\xa0添加\xc2 \xa0换行)。

    \n
  • \n
  • T\xe2\x80\x83\xe2\x80\x83\n如果上述替代命令失败(没有\xe2\x80\x99找到模式),\n跳转到\xc2\xa0the\xc2\xa0script 和\xc2\的末尾xa0read the \xc2\xa0next line of \xc2\xa0input.\xc2\xa0\n文档T

    \n
    \n

    T label

      \n如果没有s///成功替换\n自从读取了最后一个输入行并且自从\xc2\xa0lasttT命令之后,\n则分支到label;\xe2\x80\x82,如果label省略了\xc2\xa0,则分支到脚本末尾。 \xc2\xa0\n这是一个 GNU 扩展。

    \n

    \n

    因此,\xe2\x80\x99 就是我们使用标签dummy\xe2\x80\x94\n 执行此操作的原因,以便 T命令\n只查看前一个s命令。

    \n
  • \n
  • s/.*([a-zA-Z]{3}[0-9]{4}\\n)/\\1/\xe2\x80\x83\n查找 OP\xe2\x80\x99s 正则表达式,前面有任意数量的任意字符 ( .*)\n和\xc2\xa0,后跟 \xc2\xa0 换行符,\n并将它们替换为正则表达式匹配项和换行符\n(即\xc2\xa0删除正则表达式匹配之前的任何文本)。\xc2\xa0\n乍一看\xc2\xa0,这看起来可能会找到\xc2\xa0该行的最后一个匹配项,\因为.*贪婪。\xc2\xa0\n但是它找到了第一个,因为只有第一个匹配\n后面跟着一个换行符(因为第一个s是\xe2\x80\x99t g lobal)。

    \n
  • \n
  • P\xe2\x80\x83\n (大写P \xe2\x80\x83\n通过第一个换行符打印模式缓冲区。\xc2\xa0\n这只是与 \xc2\xa0regex\n 匹配的字符串(就像grep\xc2\xa0-o会输出什么)。

    \n
  • \n
  • D\xe2\x80\x83\xe2\x80\x83\n通过第一个换行符删除模式缓冲区\n和\xc2\xa0跳转到脚本的开头。

    \n
  • \n
\n


Qua*_*tal 6

使用 GNU sed 在管道中调用两次可以获得与 grep 相同的输出:

sed -E 's/[a-zA-Z]{3}[0-9]{4}/\n&\n/g' input \ 
 | sed -E '/^[a-zA-Z]{3}[0-9]{4}$/!d'
Run Code Online (Sandbox Code Playgroud)

在概念上:

sed    -E 's/REGEX/\n&\n/g' input \ 
 | sed -E '/^REGEX$/!d'
Run Code Online (Sandbox Code Playgroud)

第一个调用将匹配的正则表达式与周围的换行符隔离。

第二个调用deletes与正则表达式不匹配的所有行。

实际上,它只打印与正则表达式完全匹配的行grep -o

尝试使用一些扩展的正则表达式来匹配,并删除前导或尾随不需要的部分意味着失败。正则表达式引擎将匹配太多(因为任何*)不受限制并且会匹配as much as possible。构建具有环视匹配的 PCRE 可能会解决此问题,但 sed(任何当今的 sed)无法使用 PCRE。

这个解决方案很简单,没有已知的问题(除了如果正则表达式可以匹配“无”它会打印许多空行)。

尝试将这种使用减少到单行 sed 变得(令人惊讶地)相当复杂。其他答案试图通过几个极端情况和复杂的 sed 语法来完成此任务。

我们将继续努力寻找通用解决方案。