Answers:
首先,请注意,单个斜杠匹配太多:
$ echo $'eegg \n e.g.' | grep e\.g\.
eegg
e.g.
就Bash而言,转义时间与转义时间相同。Bash将这段时间传递给grep。对于grep,句点匹配任何内容。
现在,考虑:
$ echo $'eegg \n e.g.' | grep e\\.g\\.
e.g.
$ echo $'eegg \n e.g.' | grep e\\\.g\\\.
e.g.
$ echo $'eegg \n e.g.' | grep e\\\\.g\\\\.
$
当Bash看到一个双斜杠时,将其减为一个斜杠并将其传递给grep,在上面的三个测试中的第一个测试中,grep根据需要在一个句点之前看到一个单斜杠。因此,这做对了。
使用三斜杠,Bash将前两个斜杠减少为一个斜杠。然后看到\.
。由于转义期对Bash没有特殊意义,因此可以将其缩短为简单期。结果是,grep在我们想要的时候在句号之前看到了一个斜线。
通过四个斜杠,Bash将每对减为一个斜杠。Bash传递给grep两个斜杠和一个句点。grep看到两个斜杠和一个句点,并将两个斜杠减少为单个文字斜杠。除非输入的文字斜杠后跟任何字符,否则没有匹配项。
为了说明最后一点,请记住在单引号内所有字符都是文字。因此,给定以下三行输入,grep命令仅在输入中带有文字斜杠的行上匹配:
$ echo 'eegg
e.g.
e\.g\.' | grep e\\\\.g\\\\.
e\.g\.
对于Bash,规则是
两个斜杠减少为一个斜杠。
普通字符前面的斜线(例如句点)只是普通字符(句号)。
从而:
$ echo \. \\. \\\. \\\\.
. \. \. \\.
有一种避免所有这些混乱的简单方法:在Bash命令行上,正则表达式应放在单引号中。在单引号内,Bash保留所有内容。
$ echo '\. \\. \\\. \\\\.' # Note single-quotes
\. \\. \\\. \\\\.
echo
说明在这些情况下bash的功能的声明。
\.
或.
。对于bash来说,两者是相同的:它们相当于一个普通的时期。因此,总的来说,bash传递给grep的两者是相同的:单斜杠后跟一个句点。
echo
由于该程序的许多实现,因此使用不是测试regexp的可靠方法。例如在我的zsh(内置echo)下echo \. \\. \\\. \\\\. \\\\\.
给出. \. \. \. \.
,但/bin/echo \. \\. \\\. \\\\. \\\\\.
返回. \. \. \\. \\.
。喜欢的东西printf "%s" ...
可能是更好的办法。
输出仅对于您的字符串是相同的,但是通常那些正则表达式执行不同的操作。让我们通过添加第二个图案e,g,
(带逗号),第三个e\.g\.
(点),第四个e\,g\,
(逗号)和-o
grep选项(仅打印匹配的部分)来对示例进行一些修改。
在以下情况下.
(通知匹配任何字符''
左右e.g.
,以后我会走到那)
$ grep -o 'e.g.' <<< grep -o 'e.g.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
e.g.
e,g,
接下来,我们.
使用反斜杠进行转义\
,因此.
将仅匹配文字:
$ grep -o 'e\.g\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
e.g.
但是我们可以\
使用another 来转义\
,这样文字\
将匹配后跟.
(即任何char):
$ grep -o 'e\\.g\\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
e\.g\.
e\,g\,
但是,如果我们想只匹配\.
不\,
那么又\
需要逃脱点的特殊含义:
$ grep -o 'e\\\.g\\\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
e\.g\.
现在,因为您没有''
在grep参数周围使用,所以您需要添加另一个反斜杠来避免反斜杠从shell解释中退出,因此:
grep 'e\.g\.' => grep e\\.g\\.
grep 'e\\.g\\.' => grep e\\\\.g\\\\. (each backslash has to be quoted separately)
grep 'e\\\.g\\\.' => grep e\\\\\\.g\\\\\\. (3 x 2 = 6 backslashes in total)
当您执行时grep e\.g\.
,shell会消耗反斜杠,因此您正在执行grep e.g.
,该匹配。当您执行时grep e\\.g\\.
,shell再次使用斜杠,而现在您正在执行grep e\.\g.
,再次匹配。现在,外壳的反斜杠看起来像\\
。因此,当具有时\\
,第一个是转义序列,第二个是文字反斜杠。当您执行a时grep e\\\.g\\\.
,它仍然最终会存在grep e\.\g.
,因为\
在第一个\
将其变为文字之前没有转义序列()\
。请记住\是一个反斜杠,因此grep e\\\\.\\\\g
最终成为grep e\\.g\\.
,显然不匹配。
要查看外壳如何查看您在做什么,请使用echo(例如echo grep e\\.g\\. <<< "this is an e.g. wow"
vs echo grep e\\\\.g\\\\. <<< "this is an e.g. wow"
)。
这两个命令只为您的输入产生相同的输出,否则它们是不同的。对于什么是对我们怎么理解必须知道如何为参数首先解释bash
,然后通过grep
。
\
是一个特殊字符,它取消了后续字符(包括\
其自身)的特殊含义。如果以下字符没有特殊含义,则将其原封不动地传递。命令和结果示例:
echo \a
:a
-普通字符转义给出字符echo \\
:\
—转义的特殊字符赋予该字符echo \\\a
:\a
—特殊组合,普通echo \\\\
:\\
—特殊组合,特殊echo
bash
解释后将打印结果字符串。更多信息:bash文档,bash黑客Wiki,POSIX规范。
.
在中没有特殊含义bash
。这是外壳的普通字符。以下是与您的示例相关的序列:
echo .
: .
echo \.
: .
echo \\.
: \.
echo \\\.
: \.
echo \\\\.
: \\.
要从字面上传递参数,bash
可以使用单引号'
转义。在单引号之间,您不必关心字符的特殊含义,因为单引号是唯一具有特殊含义的字符。您可以在将字符串的第一部分括起来之后插入单引号。例如
echo 'part1'\''part2'
: part1'part2
\
是转义字符,含义与中的相似bash
。.
是一个特殊字符,表示任何字符的一次出现。请参阅:POSIX regex,GNU grep regex。正则表达式的示例:
.
—匹配任何字符,例如a
或.
\.
—仅从.
字面上匹配在下面每个示例的第二行,您都将找到等效的单引号'
,该单引号显示了传递bash
给的文字字符串grep
。然后,在grep
执行转义后,示例中唯一可能的特殊字符.
与任何字符都匹配。第三行上有一个表达式匹配的描述。
grep e.g. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
任何字符g
任何字符 - 匹配e.g.
,可能还包含其他字符串,例如eagb
grep e\.g\. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
任何字符g
任何字符 - 匹配e.g.
,可能还包含其他字符串,例如exgy
grep e\\.g\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
从字面上看- 仅匹配e.g.
grep e\\\.g\\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
从字面上看- 仅匹配e.g.
grep e\\\\.g\\\\. <<< "this is an e.g. wow"
grep 'e\\.g\\.' <<< "this is an e.g. wow"
e\
任何字符g\
任何字符 - 不匹配e.g.
\\\.
grep并给予\.
它,但事实并非如此。好问题