grepは検索パターンに一致する単語のみを表示できますか?


684

検索式に一致するファイルからgrepに「単語」を出力させる方法はありますか?

たとえば、「th」のすべてのインスタンスをいくつかのファイルで検索したい場合は、次のようにします。

grep "th" *

しかし、出力は次のようなものになります(太字は私が作成したものです)。

いくつかのテキストファイル:猫が上に座っマット  
いくつかの-他のテキストファイル:速い茶色のキツネ  
まだ別のテキストファイル:これ完全に説明できる 

同じ検索を使用して出力するものは次のとおりです。

the
the
the
this
thoroughly

これはgrepを使用して可能ですか?または別のツールの組み合わせを使用していますか?


2
ダンミッドウッドのソリューションは完璧に機能し、評価に値します。
2015年

行を変更せずにそれらの一致した単語を印刷できる方法はありますか?むしろ一致した文字列は同じ行に留まるべきですか?
言語学者

回答:


954

grep -oを試してください

grep -oh "\w*th\w*" *

編集:フィルのコメントからのマッチング

ドキュメントから:

-h, --no-filename
    Suppress the prefixing of file names on output. This is the default
    when there is only  one  file  (or only standard input) to search.
-o, --only-matching
    Print  only  the matched (non-empty) parts of a matching line,
    with each such part on a separate output line.

9
@ user181548、grep -oオプションはGNU grepでのみ機能します。したがって、GNU grepを使用していない場合は、機能しない可能性があります。
ksinkar 2014

5
@ABB一致したファイルの名前を表示するかどうかによって異なります。どのような条件下で表示されないのかはわかりませんが、複数のディレクトリでgrepを使用すると、一致したすべてのファイルの完全なファイルパスが表示されましたが、-hを指定すると、どのファイルであるかの指定なしで一致した単語。ですから、元の質問と一致させるためには、特定の状況で必要になると思います。
LokMac

1
どういう"\w*th\w*" *意味なのか説明が必要だったので投稿しようと思いました。\wは[_ [:alnum:]]なので、これは基本的に「th」を含むすべての「単語」に一致します(\wスペースは含まれないため)。引用セクションの後の*は、どのファイル(つまり、このディレクトリ内のすべてのファイルに一致するか)のグロブです
jeremysprofile

1
\wには一般的に移植できませんgrep -E。適切な移植性のために、[[:alnum:]]代わりにPOSIX文字クラス名を使用して[_[:alnum:]]ください(または、本当にアンダースコアが必要なgrep -P場合、またはプラットフォームにそれがある場合は試してください)。
tripleee 2018年

@ABB OPが示す望ましい出力を考えると、これ-hは完全に必要だと思います。
El Ronnoco

81

クロスディストリビューションの安全な回答(Windows minGWを含む?)

grep -h "[[:alpha:]]*th[[:alpha:]]*" 'filename' | tr ' ' '\n' | grep -h "[[:alpha:]]*th[[:alpha:]]*"

-oオプションを含まない古いバージョンのgrep(2.4.2など)を使用している場合。上記を使用してください。または、以下のバージョンを維持するために、より単純な方法を使用します。

Linuxクロスディストリビューションの安全な回答

grep -oh "[[:alpha:]]*th[[:alpha:]]*" 'filename'

要約-ohすると、正規表現がvim / etcで機能することを期待するのと同じように、正規表現がファイルの内容(ファイル名ではなく)に一致するものを出力します。検索する単語または正規表現は次のとおりです。君は!Perl構文ではなくPOSIXにとどまっている限り(以下を参照)

grepのマニュアルの詳細

-o      Print each match, but only the match, not the entire line.
-h      Never print filename headers (i.e. filenames) with output lines.
-w      The expression is searched for as a word (as if surrounded by
         `[[:<:]]' and `[[:>:]]';

元の答えが誰にとってもうまくいかない理由

の使用は\w、拡張された「perl」構文であるため、プラットフォームごとに異なります。そのため、POSIX文字クラスでの動作に限定されているgrepのインストールでは[[:alpha:]]、perlに相当するものではなく、を使用し\wます。詳細については、正規表現のWikipediaページを参照してください

最終的に、上記のPOSIXの回答は、grepのプラットフォーム(オリジナル)に関係なく、はるかに信頼性が高くなります。

-oオプションなしのgrepのサポートに関しては、最初のgrepは関連する行を出力し、trはスペースを新しい行に分割し、最後のgrepはそれぞれの行のみをフィルタリングします。

(PS:私はほとんどのプラットフォームを今までに知っています、\ w ....のためにパッチが当てられているでしょうが、遅れているものは常にあります)

@AdamRosenfield回答の「-o」回避策のクレジット


1
(承認された回答のコメントでksinkarが言及したように)-gはGNU grepでのみ機能しますか?
ブリリアント

@Brilliandうーん、「-o」をサポートしていないLinux実装を見つけるのに問題があるので、どのプラットフォームをチェックするかわかっていれば、回避策を探すことができます。
PicoCreator 2015年

@pico -o:オプションgitのパッケージ(?MinGWの)とそのインストールをgrep検索窓に存在していない "c:\Program Files (x86)\Git\bin\grep" --version grep (GNU grep) 2.4.2
ブルース・ピーターソン

@BrucePeterson -oのAdamRosenfieldの回避策の回答に追加しました。Windowsのgitにtr / sedとそのバージョンが含まれているかどうかを確認してください。したがって、この回避策が機能するかどうかを確認できます
PicoCreator 2015

@pico:GITの場合:GNU sedバージョン4.2.1、tr(GNU textutils)2.0
Bruce Peterson、

45

思ったより簡単です。これを試して:

egrep -wo 'th.[a-z]*' filename.txt #### (Case Sensitive)

egrep -iwo 'th.[a-z]*' filename.txt  ### (Case Insensitive)

どこ、

 egrep: Grep will work with extended regular expression.
 w    : Matches only word/words instead of substring.
 o    : Display only matched pattern instead of whole line.
 i    : If u want to ignore case sensitivity.

2
これは、4年以上前の既存の回答に何も追加しないようです。
tripleee 2018年

3
@tripleee私は自分のアプローチの方が簡単で優れていると思ったので、これを投稿しました。
Abhinandan prasad

42

スペースを改行に変換してからgrepを実行できます。例:

cat * | tr ' ' '\n' | grep th

18
猫いらない。tr '' '\ n' <ファイル| グレップth。大きなファイルの場合は遅くなります。
ghostdog74

これはうまくいきませんでした。出力には、ファイル名と、一致を含むファイルの行全体が含まれています。とにかく、提供されている他のソリューションの1つが機能しました。入力ありがとうございます。
ニールボールドウィン

@ ghostdog74:良い点ですが、ファイル以上のファイルがある場合は、猫を使用する必要があります。@ニール・ボールドウィン:あなたはそれを正しいタイプで入力しましたか?入力ファイルが1つしかない場合(この場合はstdin)、grepはファイル名を出力しません。
Adam Rosenfield、

@Adam-はい、申し訳ありませんが、Adamは1つのファイルで機能しますが、複数では機能しません。
ニールボールドウィン

4
@ ghostdog74遅い部分があるためであるならばtr、彼が行うことができ、grepそう、最初trだけ一致した行に適用されます:grep th filename | tr ' ' '\n' | grep th
Carcamano

37

ただawk、ツールの組み合わせは必要ありません。

# awk '{for(i=1;i<=NF;i++){if($i~/^th/){print $i}}}' file
the
the
the
this
thoroughly

8
@AjeetGangaよく、それは名前にあります
Daerdemandt

11

一致とperlのみのgrepコマンド

grep -o -P 'th.*? ' filename

3
一致したグループのみの表示はどうですか?
Bishwas Mishra 2018

これは機能しません。thワイルドカードの可能な限り最短の繰り返しを要求したので、それだけが見つかります。
tripleee 2018年

@tripleee-正規表現の末尾にスペースが含まれているため、問題は発生しません。ただし、行末など、スペースが含まれていない単語は検出されません。
ケンウィリアムズ

8

私はawkの構文を覚えるのが難しいことに満足していませんでしたが、これを行うために1つのユーティリティを使用するという考えは気に入りました。

ack(Ubuntuを使用している場合はack-grep)でこれを簡単に実行できるようです。

# ack-grep -ho "\bth.*?\b" *

the
the
the
this
thoroughly

-hフラグを省略すると、次のようになります。

# ack-grep -o "\bth.*?\b" *

some-other-text-file
1:the

some-text-file
1:the
the

yet-another-text-file
1:this
thoroughly

おまけとして、--outputフラグを使用してこれを行うと、私が見つけた最も簡単な構文で、より複雑な検索を行うことができます。

# echo "bug: 1, id: 5, time: 12/27/2010" > test-file
# ack-grep -ho "bug: (\d*), id: (\d*), time: (.*)" --output '$1, $2, $3' test-file

1, 5, 12/27/2010


4

「icon-」で始まるすべての単語を検索するには、次のコマンドが最適です。ここでは、grepに似たAckを使用していますが、オプションと書式設定が優れています。

ack -oh --type=html "\w*icon-\w*" | sort | uniq

3

pcregrepを試すこともできます。grepに-wオプションがありますが、期待どおりに動作しない場合があります。

ウィキペディアから:

cat fruitlist.txt
apple
apples
pineapple
apple-
apple-fruit
fruit-apple

grep -w apple fruitlist.txt
apple
apple-
apple-fruit
fruit-apple

3

同様の問題があり、grep / pattern regexと「一致したパターンが見つかりました」を出力として探していました。

最後に、オプション-oを指定してegrepを使用しました(grep -eまたは-Gで同じ正規表現ではegrepの同じ結果が得られませんでした)。

だから、私は(私は正規表現マスターではありません)に似ていると思う:

egrep -o "the*|this{1}|thoroughly{1}" filename

不要な{1}数量詞は削除する必要があります。または、一貫性をt{1}h{1}e{1}
保ち

同じ行で印刷できますか?
吴毅凡

-1

次のようにgrep出力をPerlにパイプすることができます。

grep "th" * | perl -n -e'while(/(\w*th\w*)/g) {print "$1\n"}'

9
それは正しい結果を与えません。また、Perlを使用している場合、grepを使用する必要はありません。Perlですべてを行います。
ghostdog74 09/10/10

エラーを指摘してくれてありがとう、ghostdog74。最初の単語だけでなく、行のすべての単語を印刷するように変更しました。

私が言ったように、grepは必要ありません。perl -n -e'while(/(\ s + th \ w *)/ g){print "$ 1 \ n"} 'ファイル
ghostdog74

7
あなた次第。ポイントを示しています。必要がない場合は、行わないでください。その余分な "|" あなたにもう一つのプロセスがかかります。
ghostdog74 09/10/10

1
Perl 5.10以降の場合:perl -nE '@a = /(regexp)/ ig; 「\ n」、@ aに参加してください
Photon教授、

-1
$ grep -w

grep manページからの抜粋:

-w:単語全体を形成する一致を含む行のみを選択します。テストは、一致する部分文字列が行の先頭にあるか、単語の構成文字の前にないことです。


1
それでも一致を含む行全体が印刷されます。実際の一致を制限して、the「これら」や「入浴」などの一致を解除します。
Tripleee、2014年

-6

ripgrep

以下は使用例ripgrepです。

rg -o "(\w+)?th(\w+)?"

に一致するすべての単語に一致しthます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.