有一种简单的方式来传递一个“原始”的字符串到grep?(Is there an easy way t

2019-06-17 16:09发布

grep从命令行使用时,将不能输入“原始”的字符串,由于某些字符需要转义到不会被视为文字。 例如:

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

我用printf来自动转义字符串:

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

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

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

但是,它显然不是意味着这样的:在输出一些字符不会被转义,有些是不必要如此。 例如:

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

^传递到时字符不应该逃脱grep

是否有一个命令行工具,它需要一个原始字符串,并返回可直接用作使用grep模式字符串的一个bash转义版本 ? 我怎样才能在纯bash中实现这一点,如果不是?

Answer 1:

如果您正在试图将grep使用扩展正则表达式语法,做到这一点的方法是使用grep -E (又名egrep )。 你也应该知道grep -F (又名fgrep ),在GNU Coreutils的,较新版本grep -P

背景:原来grep有一个相当小的集合regex操作符的; 这是肯·汤普森的原正则表达式的实现。 新版本具有扩展的曲目,后来发展以及对兼容性的原因,有一个不同的名称。 随着GNU grep ,只有一个二进制文件,如果调用作为理解传统,基本语法RE grep ,和ERE如果援引作为egrep 。 从一些结构egrep是可用grep用一个反斜杠逃逸引进特殊的意义。

随后,Perl的编程语言,甚至进一步扩展的形式主义; 此正则表达式方言似乎是大多数新人错误地期待grep ,也支持。 随着grep -P ,它; 但这还没有得到广泛支持的所有平台。

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

egrep ,以下字符也有特殊的意义: ()|+?{} (用于重复的括号都不在原始egrep 。)该分组括号也使反向引用与\1\2

在许多版本grep ,你可以得到egrep通过把一个反斜杠之前的行为egrep特价商品。 也有像特殊序列\<\>

在Perl中,一个巨大的类似附加逃逸数\w \s \d进行了介绍。 Perl 5中,正则表达式设施被大大延长,与非贪婪匹配*? +? 等,非分组圆括号(?:...)向前看符号,lookbehinds等。

......话说回来,如果你真的想要转换egrep正则表达式grep正则表达式,而不调用任何外部的过程中 ,尽量${regex/pattern/substitution}每个的egrep特殊字符; 但我们也承认这种不处理的字符类,否定的字符类或反斜线正确逃逸。



Answer 2:

如果你要搜索一个确切的字符串,

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

-F告诉grep为IS治疗模式,没有解释的正则表达式。

(这往往是可作为fgrep为好。)



Answer 3:

当我使用grep -E利用用户提供的字符串我逃脱他们本

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

例如运行

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

这样,您就可以安全地插入您的正则表达式中的引号的字符串。

例如,如果你想找到的每一行开始与用户的内容,以向用户提供有趣的字符串作为*。

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


Answer 4:

我认为,以前的答案是不完整的,因为他们错过了一个重要的事情,即与划线开头的字符串( - )。 因此,尽管这将无法工作:

echo "A-B-C" | grep -F "-B-"

这一次将:

echo "A-B-C" | grep -F -- "-B-"


文章来源: Is there an easy way to pass a “raw” string to grep?