我正试图抓住我的名字 369从 file.txt 我用正则表达式输入了这个 grep 行,但它返回一个错误。我尝试过使用egrep
,但没有成功。
输入:
- 我的名字 369 == 匹配
- 我的名字 161 == 匹配
- my_name 123 2 != 错误
错误: ?!.: command not found
这是我要执行的代码并且它有效正则表达式101
grep -i "^\s*my_name\s+[0-9]+\s*$(?!.)*" file.txt
答案1
看起来你想要:
grep -Ex '[[:space:]]*my_name[[:space:]]+[0123456789]+[[:space:]]*' file.txt
- 在双引号内,
$(cmd)
它扩展为 的输出cmd
,称为命令替换仍在执行。在这里,您试图获取?!.
命令的输出,但该命令不存在,因此会出现错误。由于许多正则表达式运算符碰巧在 shell 中也具有特殊含义,因此最好使用单引号来引用它们,因为它们会转义每一个shell 的字符。 \s
并且(?!.)
是珀尔正则表达式运算符。虽然现在有些grep
实现确实支持\s
(作为标准的缩写形式[[:space:]]
),但它们不能支持(?!.)
负向前看运算符,因为(?!
需要匹配文字,(?!
因为它自grep
70 年代初引入以来一直如此。他们可以使用-E
(由 POSIX 在 90 年代初引入)来识别它,因为标准扩展正则表达式 (ERE)(?...
未指定。E
ast-open 的实现grep
就是这样做的,但这是我所知道的唯一一种。无论如何,在 后面添加任何内容$
(旨在匹配主题末尾)是没有意义的。*
在环视运算符之后添加量词(在您的情况下)也是没有意义的。+
是 ERE 或 Perl RE 运算符,而不是 BRE 运算符。 BRE 等效项是\{1,\}
.[0-9]
确实匹配 0123456789 ASCII 阿拉伯数字,但通常有更多(通常与数字相关)字符恰好在 0 和 9 之间排序。如果(就像进行输入验证时一样)您只想匹配 0123456789,则需要指定确切的列表。- 添加
-x
以匹配整个线可以节省使用^
和$
锚点的麻烦。 -i
用于不区分大小写的匹配。有了它,MY_NAME
,My_NaMe
也会被接受。- 我
-E
在上面使用只是因为+
打字比\{1,\}
只是装饰性的要短。此处使用 ERE 并不是绝对必要的。 - do的某些实现
grep
支持-P
使用类似 Perl 的正则表达式进行匹配的选项。有了这些,你就可以做到grep -Px '\s*my_name\s+\d+\s*'
。\d
旨在匹配十进制数字。在我尝试过的GNU版本中grep
,它只匹配0123456789,但我不能保证所有版本和实现都是如此。例如,请参阅grep -Px '(*UCP)\d'
(对于U
nicodeC
字符属性)如何P
匹配更多十进制数字字符。为了安全起见,您可能仍然想在[0123456789]
那里使用。
另一种方法是使用awk
并执行:
awk 'NF == 2 && $1 == "my_name" && $2 ~ /^[0123456789]+$/'
为了更清楚地指定您想要具有两个字段(其中N
字段数F
为 2)的行,第一个字段是my_name
,第二个字段仅由 ASCII 十进制数字组成。默认情况下,字段用空格分隔(更像是[[:blank:]]
),尽管某些awk
实现仅考虑空格和制表符,有些还考虑垂直间距字符,例如[[:space:]]
/ \s
do。
对于不区分大小写的匹配,你会这样做tolower($1) == "my_name"
。 GNU 实现awk
可以通过传递 来对所有正则表达式匹配进行不区分大小写的匹配-v IGNORECASE=1
。
1 从技术上讲,?!.
它是一个 shell glob,也是?
一个 glob 运算符。因此,如果当前工作目录中有被调用的文件a!.
,b!.
那么该文件将扩展到这些文件,并且您将尝试使用作为参数执行a!.
命令。b!.
使用 zsh 或 Fish 等更理智的 shell(另请参阅failglob
中的选项),当它与任何文件都不匹配bash
时,您会收到错误消息。?!.