Bash:简单的方法来传递一个“原始”string到grep?

从命令行使用grep时,不能input“raw”string,因为某些字符需要转义而不被视为文字。 例如:

 $ grep '(hello|bye)' # WON'T MATCH 'hello' $ grep '\(hello\|bye\)' # GOOD, BUT QUICKLY BECOMES UNREADABLE 

我正在使用printf来自动转义string:

 $ printf '%q' '(some|group)\n' \(some\|group\)\\n 

这会产生一个bash转义的string版本,并使用反引号,这可以很容易地传递给一个grep调用:

 $ grep `printf '%q' '(a|b|c)'` 

但是,显然这并不意味着:输出中的某些字符不会被转义,有些字符是不必要的。 例如:

 $ printf '%q' '(^#)' \(\^#\) 

传递给grep时, ^字符不应该被转义。

是否有一个cli工具,需要一个原始的string,并返回一个可以直接用作grep模式的string的bash转义版本 ? 如果没有,我怎么能在纯粹的bash中实现这个呢?

如果您试图让grep使用扩展的正则expression式语法,那么做的方法是使用grep -E (又名egrep )。 你也应该知道grep -F (又名fgrep ),在GNU Coreutils的更新版本中, grep -P

背景:原始的grep只有一小部分正则expression式, 这是Ken Thompson最初的正则expression式实现。 随后开发了一个带有扩展库的新版本,出于兼容性原因,获得了不同的名称。 使用GNU grep ,只有一个二进制文件,它理解传统的基本RE语法(如果调用grep ,而ERE(如果调用egrepegrep中的一些构造可以通过使用反斜杠转义来引入特殊的意义。

随后,Perl编程语言更进一步扩展了forms化; 这个正则expression式似乎是大多数新手错误地期望grep支持的。 用grep -P ,它确实; 但是在所有平台上还没有得到广泛的支持。

所以,在grep ,以下字符有特殊含义: ^$[]*.\

egrep ,下列字符也有特殊含义:( ()|+?{} 。 (重复的大括号不在原始的egrep )。分组括号还可以对\1\2等进行反向引用。

在许多版本的grep ,可以通过在egrep特殊项之前加一个反斜杠来获得egrep行为。 还有像\<\>这样的特殊序列。

在Perl中,引入了大量额外的转义,例如\w \s \d 。 在Perl 5中,正则expression式的工具大大扩展了,而非贪婪匹配*? +? 非分组括号(?:...) ,向前看,向后看,等等。

…话虽如此,如果你真的想在不调用任何外部进程的情况下egrep正则expression式转换为grep正则expression式,请为每个egrep特殊字符尝试${regex/pattern/substitution} ; 但要认识到这不能正确处理字符类,否定字符类或反斜杠转义。

如果你想search一个确切的string,

 grep -F '(some|group)\n' ... 

-F告诉grep按照原样处理这个模式,而不是作为正则expression式的解释。

(这通常也可以作为fgrep 。)

当我用grep -E用户提供的string时,我用这个来逃避它们

 ere_quote() { sed 's/[]\.|$(){}?+*^]/\\&/g' <<< "$*" } 

示例运行

 ere_quote ' \ $ [ ] ( ) { } | ^ . ? + *' # output # \\ \$ \[ \] \( \) \{ \} \| \^ \. \? \+ \* 

这样你可以安全地在你的正则expression式中插入带引号的string。

例如,如果您想查找以用户内容开始的每一行,并且用户提供有趣的string为*。

 userdata=".*" grep -E "^$(ere_quote "$userdata")" <<< ".*hello" # if you have colors in grep you'll see only ".*" in red 

很有用! 只是想指出,我相信它有一个小错误(请纠正我,如果我错了):

代替:

sed 's/[] ...

是: sed 's/[[] ...为了检测“ [ ”字符

我认为以前的答案是不完整的,因为他们错过了一个重要的事情,即string以破折号( – )开头。 所以虽然这不起作用:

 echo "ABC" | grep -F "-B-" 

这个将会:

 echo "ABC" | grep -F -- "-B-"