Grepは語幹を検索し、単語のみを印刷します(行を除く)。

Grepは語幹を検索し、単語のみを印刷します(行を除く)。

正規表現で見つかった一致する単語だけを印刷しようとしています。以下では、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個以上の先行原子*シェルワイルドカード演算子と混同しています。0文字以上

OPENSSL_NO_*OPENSSL_NO後ろにゼロ以上の下線があることを示します。

あなたが望むもの:

grep -o 'OPENSSL_NO_.*'

.単一文字に一致する正規表現演算子はどこにありますか?

または:

grep -o 'OPENSSL_NO_[[:alnum:]]*'

ゼロ個以上の英数字(ロケールでサポートされているすべてのアルファベットスクリプト)

拡大する正規表現(例grep -E:)にも次のものがあります+1つ以上の先行原子。そして基本的な代わりに正規表現(-Eを除く)を使用できます\{1,\}

一部の実装にはこの意味grepもあります。\w英数字または下線ただし、一部の実装の一部のバージョンではこれに限定されますA-Za-z0-9

とにかく標準-o的な-Rオプションではないことに注意してください。 POSIXlyでは、次のことができます。

sed -n 's/.*\(OPENSSL_NO_[[:alnum:]_]\{1,\}\).*/\1/p' < file

(1行に1回のみ発生する可能性があり、複数回発生した場合は一番右の項目のみが表示されます。)

ファイル名は印刷されません。これを行うには、次のものを使用できますawk

find . -name '*.[hc]' -type f -exec awk 'match($0, /OPENSSL_NO_[[:alnum:]_]+/) {
  print FILENAME": "substr($0, RSTART, RLENGTH)}' {} +

答え2

正規表現の演算子は*「0個以上」を意味するため、grepは「0」個の追加文字を使用してその条件を満たします。

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

関連情報