为什么 grep 在这种情况下不能正常工作?

Joh*_*lor 2 grep string files

考虑文件 file2.txt 具有以下内容:

P 89 24 -1.5388040474568784e+01 7.4421775186012660e+00 -1.3143195543234219e+03 1.3168884860257754e+03 8.0419002445999993e+01 44 0 0 -97 0
P 122 -4 -1.4869334602986523e+01 5.7316939411954255e+00 -1.3144161801429666e+03 1.3169704096915282e+03 8.0419002445999993e+01 44 0 0 -370 0
P 493 -24 -1.4690576431881317e+01 7.3848907323212831e+00 -1.3144620647251766e+03 1.3170224315489374e+03 8.0419002445999993e+01 62 0 0 -499 0
E 3 -1 -1.0000000000000000e+00 -1.0000000000000000e+00 -1.0000000000000000e+00 9999 0 970 1 2 0 7 1.7003962000000002e+05 8.5019810000000018e-01 8.5019810000000018e-01 8.5019810000000018e-01 3.0000000000000000e+01 3.8153441026312507e+01 1.0000000000000000e+11
E 4 -1 -1.0000000000000000e+00 -1.0000000000000000e+00 -1.0000000000000000e+00 9999 0 818 1 2 0 7 1.7003962000000002e+05 8.5019810000000018e-01 8.5019810000000018e-01 8.5019810000000018e-01 3.0000000000000000e+01 3.2509364886711985e+01 1.0000000000000000e+11
P 5 2 0 0 3.7531787088999999e+02 3.8383684055052936e+02 8.0419002445999993e+01 22 0 0 -6 0
P 8 24 7.0195398693654170e+00 3.1543502387874696e+01 5.5989200759599044e+01 1.0318077843755555e+02 8.0419002445999993e+01 44 0 0 -50 0
P 67 28 5.8271676589304882e+00 3.3476871962084061e+01 5.6723118833601163e+01 1.0411236719963519e+02 8.0419002445999993e+01 44 0 0 -168 0
P 219 13 6.0328453988772415e+00 3.3531592253635168e+01 5.6777179460595200e+01 1.0417114266715717e+02 8.0419002445999993e+01 44 0 0 -329 0
P 444 -24 6.4646967953734418e+00 3.4909545978243479e+01 5.7879920796889749e+01 1.0525098522544691e+02 8.0419002445999993e+01 62 0 0 -452 0
E 5 -1 -1.0000000000000000e+00 -1.0000000000000000e+00 -1.0000000000000000e+00 9999 0 598 1 2 0 7 1.7003962000000002e+05 0 0 8.5019810000000018e-01 3.0000000000000000e+01 6.8997318544430456e+01 1.0000000000000000e+11
Run Code Online (Sandbox Code Playgroud)

我只想提取字符串P ... 24 ...P ... -24 .... 这就是我所做的:

cat file2.txt | grep -E '(P [0-9]+ 24 | P [0-9] + -24 |P [0-9][0-9]+ 24 | P [0-9][0-9] + -24 |P [0-9][0-9][0-9] + 24 | P [0-9][0-9][0-9] + -24 |P [0-9][0-9][0-9][0-9]+ 24 | P [0-9][0-9][0-9][0-9] + -24 )' &> file3.txt
Run Code Online (Sandbox Code Playgroud)

但生成的 file3.txt 仅包含 strings P ... 24。你能告诉我我做错了什么吗?

bu5*_*man 13

.... 我究竟做错了什么?...除了使它变得更加复杂之外...您正在尝试匹配在所有情况下-24以及在其他一些情况下不在字符串中的多个空格和前导空格... 。

P [0-9]+ 24 |
Run Code Online (Sandbox Code Playgroud)

可以P,然后 是一系列数字[0-9]+,然后 24空格

| P [0-9] + -24 |
Run Code Online (Sandbox Code Playgroud)

这里的数字 之前P和之后有一个或多个空格, +后跟另一个 空格,由于额外的空格而无法匹配

|P [0-9][0-9]+ 24 |
Run Code Online (Sandbox Code Playgroud)

再次正常,尽管所有匹配都已捕获在第一个模式中,因此它是多余的

| P [0-9][0-9] + -24 |
Run Code Online (Sandbox Code Playgroud)

额外的空格,与上面相同-24...不匹配

|P [0-9][0-9][0-9] + 24 |
Run Code Online (Sandbox Code Playgroud)

之前有额外的空间,+所以它会再次寻找 2 个 或更多...

| P [0-9][0-9][0-9] + -24 |
Run Code Online (Sandbox Code Playgroud)

the 之前有前导空格,并且再次之前P有 2 个或更多空格。 -24

|P [0-9][0-9][0-9][0-9]+ 24 |
Run Code Online (Sandbox Code Playgroud)

很好但多余

| P [0-9][0-9][0-9][0-9] + -24
Run Code Online (Sandbox Code Playgroud)

the 之前有前导空格,并且再次之前P有 2 个或更多空格。 -24

虽然@gillesquenot有一个更优雅的解决方案,但如果你失去了额外的空间,你的解决方案“有效”......

grep -E '(P [0-9]+ 24 |P [0-9]+ -24 |P [0-9][0-9]+ 24 |P [0-9][0-9]+ -24 |P [0-9][0-9][0-9] + 24 |P [0-9][0-9][0-9]+ -24 |P [0-9][0-9][0-9][0-9]+ 24 |P [0-9][0-9][0-9][0-9]+ -24 )'
Run Code Online (Sandbox Code Playgroud)

如果你有多个空间的可能性

grep -E '^P +[0-9]+ +-?24'
Run Code Online (Sandbox Code Playgroud)

编辑

是一个有用的资源,可以查看任何字符串中的匹配内容和位置


Gil*_*not 12

的任务!这就是DSL \xc2\xb9:正是这种情况,这awk是要走的路。
\n简单、可重复使用、高效且快速。

\n

没有正则表达式

\n
awk \'$1 == "P" && ($3 == "-24" || $3 == "24")\' file2.txt \n
Run Code Online (Sandbox Code Playgroud)\n

或使用正则表达式

\n
awk \'$1 == "P" && $3 ~ /^-?24$/\' file2.txt \n
Run Code Online (Sandbox Code Playgroud)\n

这里,在 regex 中/^-?24$/,破折号是可选的,它允许使用这个短regex

\n
\n
正则表达式匹配如下:
\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n
节点解释
^字符串的开头
-?\'-\'(可选(匹配尽可能多的数量))
24\'24\'
$在可选的 \\n 之前和字符串末尾
\n

\n

\xc2\xb9最著名的聊天问题

\n

问:DSL 对于开发者来说意味着什么?

\n
\n

DSL(领域特定语言)是一种计算机语言,旨在使特定任务的编码变得更加容易。它是针对特定应用程序领域量身定制的,允许开发人员快速高效地编写代码。DSL 的常见用法包括数据库查询、处理文本和科学模拟。DSL 允许开发人员快速构建用于特定目的的应用程序,提供更直观的编程方法,减少对语法的依赖

\n
\n

  • @Kusalananda 我想我不同意你的观点——awk 的*预期目的可能不是那么狭窄*,但是:awk 是一种用于处理面向字符串的数据的 DSL;那是它的领域。对于编写其他程序来说确实没什么用。而且:您经常并且通常会发现 awk 程序嵌入到更通用的语言程序中,以解决特定于该领域的问题,而不是其他问题。 (3认同)

Gil*_*not 9

让我们稍微简化一下正则表达式:

grep -E '^P [0-9]+ -?24\b' file2.txt 
Run Code Online (Sandbox Code Playgroud)

正则表达式的主要问题(除了不需要的复杂性和可读性之外)是您使用了额外的错误空格。

不需要:

如果您认为输入中可以有更多的空间,则可以使用以下之一:

  • +
  • [[:space:]]+POSIX字符类)
  • \s+需要-P又名PCRE开关grep

正则表达式匹配如下:

节点 解释
^ 线锚点的起点
P ‘P’+空格
[0-9]+ 任何字符:“0”到“9”(1 次或多次(匹配尽可能多的数量))
空间
-? '-'(可选(匹配尽可能多的数量))
24 ‘24’
\b 字边界


Kus*_*nda 7

您的正则表达式似乎插入了随机空格。正则表达式中的空格将与您应用它的文本中的空格匹配。另请注意,将匹配与和[0-9]+相同的字符串(但反之则不然)。[0-9][0-9]+[0-9][0-9][0-9]+

因此,您应该能够使用

grep -E '^P [0-9]+ -?24 ' file2.txt
Run Code Online (Sandbox Code Playgroud)

请注意使用锚点来确保 与P行开头匹配,并-?匹配 之前的可选破折号24

这与另一个答案中的建议相同,除了最后我使用一个简单的空格代替非标准单词边界模式\b。如果我知道数据中有一个空格需要匹配,我就可以做到这一点,这个例子似乎表明存在这个空格。


使用 Miller ( mlr),将输入视为每行具有隐式整数索引字段(“nidx”)的文件,过滤(提取)P第一个字段中包含 a 且第三个字段的绝对值恰好为24:

$ mlr --nidx filter '$1 == "P" && abs($3) == 24' file2.txt
P 89 24 -1.5388040474568784e+01 7.4421775186012660e+00 -1.3143195543234219e+03 1.3168884860257754e+03 8.0419002445999993e+01 44 0 0 -97 0
P 493 -24 -1.4690576431881317e+01 7.3848907323212831e+00 -1.3144620647251766e+03 1.3170224315489374e+03 8.0419002445999993e+01 62 0 0 -499 0
P 8 24 7.0195398693654170e+00 3.1543502387874696e+01 5.5989200759599044e+01 1.0318077843755555e+02 8.0419002445999993e+01 44 0 0 -50 0
P 444 -24 6.4646967953734418e+00 3.4909545978243479e+01 5.7879920796889749e+01 1.0525098522544691e+02 8.0419002445999993e+01 62 0 0 -452 0
Run Code Online (Sandbox Code Playgroud)