为什么“grep -w”匹配后面带有连字符/减号(“-”)的单词?

为什么“grep -w”匹配后面带有连字符/减号(“-”)的单词?

我需要询问您有关grep在 Debian 中的 Bash 脚本中使用命令的问题。

我有包含以下几行的示例文件:

/fruit-/apple.txt
/fruit-/banana.txt
/fruit-/samples
/vegetables-/carrot.txt
/vegetables-/garlic.txt

我想选择包含 word 的所有行fruit-

我可以调用命令:

grep -w "fruit-" file.txt

输出将是:

/fruit-/apple.txt
/fruit-/banana.txt
/fruit-/samples

但是当我使用命令时:

grep -w "fruit" file.txt

我也得到与上面相同的输出。但这是错误的。输出应该是 0。因为我没有输入-模式。

为什么不正确grep对待呢-

答案1

-w选项确实告诉grep只查找fruit与“单词”匹配的行,这意味着它必须从行的开头开始,或者前面有“非单词”字符,并且在行的末尾结束或后跟“非单词”字符。

但是,根据手册页,“单词”字符grep是:

单词组成字符是字母、数字和下划线。

这意味着 是-一个“非单词”字符,并且fruit-将匹配“单词搜索”,因为fruit匹配算法将在到达 时停止-

现在,您似乎只想选择前两行之间的内容所在的行/ 正是 fruit,相对于包含图案 fruit。在这些情况下,您必须使匹配更加明确:

  • 使用grep,您可以说:
    grep "^/fruit/" file.txt
    
    这会将模式锚定到行的开头,并且仅接受-后没有的那些行fruit
  • 或者,将awk集合/用作字段分隔符:
    awk -F/ '!$1&&$2=="fruit"' file.txt
    
    这将只接受第一个字段为空(即以 a 开头/)且第二个字段恰好为 的行fruit

答案2

@AdminBee已经澄清了什么是单词意味着grep,我将添加如何告诉它在这种情况下使用单词的其他定义。

grep -w word或多或少地寻找word前面或后面都没有单词字符的 s。

某些grep实现可以-P选择切换到类似 perl 的正则表达式。

perl有明确的环视四周用于检查某些内容是否匹配之前或之后的运算符。

grep -w word分别是和的grep -P '(?<!\w)word(?!\w)'地方(?<!pattern)(?!pattern)消极地向后看运营商。

如果你想认为这-是一个单词成分,你可以将其更改为:

grep -P '(?<![\w-])fruit(?![\w-])'

它将匹配foo fruit barorfoo/fruit/barfoo/fruit但不匹配,foo/fruit-bar因为fruit后面跟着-.

或者为了任何字符,但/:

grep -P '(?<![^/])fruit(?![^/])'

或者为了空格分隔的单词:

grep -P '(?<!\S)word(?!\S)'

(其中\S,与[^\s]POSIX 类似,[^[:space:]]是任何未分类为空白的字符)。

相关内容