我试图仅打印通过正则表达式找到的匹配单词。下面,我想要OPENSSL_NO_*
源代码中存在的所有选项:
$ grep -IR OPENSSL_NO
fuzz/asn1.c:#ifndef OPENSSL_NO_RFC3779
fuzz/asn1.c:#ifndef OPENSSL_NO_RFC3779
fuzz/asn1.c:#ifndef OPENSSL_NO_CMS
fuzz/asn1.c:#ifndef OPENSSL_NO_DH
fuzz/asn1.c:#ifndef OPENSSL_NO_EC
fuzz/asn1.c:#ifndef OPENSSL_NO_RFC3779
fuzz/asn1.c:#ifndef OPENSSL_NO_OCSP
fuzz/asn1.c:#ifndef OPENSSL_NO_TS
fuzz/asn1.c:#ifndef OPENSSL_NO_DH
fuzz/asn1.c:#ifndef OPENSSL_NO_DSA
...
当我尝试通过仅打印完整单词来修剪输出时:
$ grep -oIR "OPENSSL_NO*"
fuzz/asn1.c:OPENSSL_NO
fuzz/asn1.c:OPENSSL_NO
fuzz/asn1.c:OPENSSL_NO
fuzz/asn1.c:OPENSSL_NO
fuzz/asn1.c:OPENSSL_NO
...
当我尝试 awk 时,它会打印整行:
$ grep -IR OPENSSL_NO | awk '/OPENSSL_NO[_A-Z0-9_]/{ print $0 }'
fuzz/asn1.c:#ifndef OPENSSL_NO_RFC3779
fuzz/asn1.c:#ifndef OPENSSL_NO_RFC3779
fuzz/asn1.c:#ifndef OPENSSL_NO_CMS
fuzz/asn1.c:#ifndef OPENSSL_NO_DH
fuzz/asn1.c:#ifndef OPENSSL_NO_EC
...
和:
$ grep -IR OPENSSL_NO | awk '/\<OPENSSL_NO\>'
awk: line 1: runaway regular expression /\<OPENSSL_ ...
和:
$ grep -Eo -IR 'OPENSSL_NO_[A-Z0-9_]'
fuzz/asn1.c:OPENSSL_NO_R
fuzz/asn1.c:OPENSSL_NO_R
fuzz/asn1.c:OPENSSL_NO_C
fuzz/asn1.c:OPENSSL_NO_D
fuzz/asn1.c:OPENSSL_NO_E
和:
$ grep -IR OPENSSL_NO | sed -n 's/.*\(OPENSSL_NO\).*/\1/p'
OPENSSL_NO
OPENSSL_NO
OPENSSL_NO
OPENSSL_NO
OPENSSL_NO
...
如何匹配一个单词然后只打印该单词?
考虑到有很多问题,这显然是一项痛苦的任务。以下是我无法适应我的[简单?]问题的各种问题:
答案1
*
正则表达式中的意思是0 个或多个前面的原子。您将它与*
shell 通配符运算符混淆了,它的含义是0 个或多个字符。
OPENSSL_NO_*
表示OPENSSL_NO
后面跟着0个或多个下划线。
你想要:
grep -o 'OPENSSL_NO_.*'
哪里.
是匹配单个字符的正则表达式运算符。
或者:
grep -o 'OPENSSL_NO_[[:alnum:]]*'
0 个或多个字母数字字符(在语言环境支持的任何字母脚本中)。
扩展正则表达式(如grep -E
)也有+
for1 个或多个前面的原子。和基本的正则表达式(不带 -E),您可以使用\{1,\}
它来代替。
有些grep
实现也有\w
这意味着任何字母数字字符或下划线但请注意,在某些实现的某些版本中,它仅限于此A-Za-z0-9
。
无论如何,请注意-o
/-R
不是标准选项。 POSIXly,你可能想要:
sed -n 's/.*\(OPENSSL_NO_[[:alnum:]_]\{1,\}\).*/\1/p' < file
(每行只允许出现一次;如果出现多个,则只显示最右边的一个)。
这不会打印文件名。为此,您可以使用awk
:
find . -name '*.[hc]' -type f -exec awk 'match($0, /OPENSSL_NO_[[:alnum:]_]+/) {
print FILENAME": "substr($0, RSTART, RLENGTH)}' {} +
答案2
正则表达式中的运算符*
意味着“零个或多个”,因此 grep 非常乐意通过使用“零”个附加字符来满足该条件。
我将以某种方式扩展正则表达式,以便 grep 被迫包含该术语的其余部分:
grep -o 'OPENSSL_NO_.*$' input
或者
grep -o 'OPENSSL_NO_.*\b' input
(在这两种情况下,我都添加了一个额外的下划线)。
答案3
我已经使用 awk 命令来实现相同的目的
for i in {1..2}; do awk -v i="$i" '$i ~/^OPENSSL/ {print $i}' example.txt; done
输出
OPENSSL_NO_RFC3779
OPENSSL_NO_RFC3779
OPENSSL_NO_CMS
OPENSSL_NO_DH
OPENSSL_NO_EC
OPENSSL_NO_RFC3779
OPENSSL_NO_OCSP
OPENSSL_NO_TS
OPENSSL_NO_DH
OPENSSL_NO_DSA