2つのパターンのいずれかに一致する複数のファイル内のすべての行を検索したい。入力して探しているパターンを見つけようとしました
grep (foo|bar) *.txt
しかし、シェルは|
をパイプとして解釈し、bar
が実行可能ファイルでない場合は文句を言います。
同じファイルセット内の複数のパターンをgrepするにはどうすればよいですか?
egrep "foo|bar" *.txt
または
grep "foo\|bar" *.txt
grep -E "foo|bar" *.txt
gnu-grepのmanページを選択的に引用します:
-E, --extended-regexp
Interpret PATTERN as an extended regular expression (ERE, see below). (-E is specified by POSIX.)
Matching Control
-e PATTERN, --regexp=PATTERN
Use PATTERN as the pattern. This can be used to specify multiple search patterns, or to protect a pattern
beginning with a hyphen (-). (-e is specified by POSIX.)
(...)
grep understands two different versions of regular expression syntax: “basic” and “extended.” In GNU grep, there
is no difference in available functionality using either syntax. In other implementations, basic regular
expressions are less powerful. The following description applies to extended regular expressions; differences for
basic regular expressions are summarized afterwards.
最初は読みませんでしたので、微妙な違いを認識できませんでした。
Basic vs Extended Regular Expressions
In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the
backslashed versions \?, \+, \{, \|, \(, and \).
例から学んだので、私はいつもegrepと不必要に括弧を使いました。今、私は何か新しいことを学びました。 :)
TC1が言ったように、-F
は使用可能なオプションのようです:
$> cat text
some text
foo
another text
bar
end of file
$> patterns="foo
bar"
$> grep -F "${patterns}" text
foo
bar
まず、特殊文字には引用符を使用する必要があります。第二に、それでも、grep
は代替を直接理解しません。 egrep
を使用する必要があります、または(GNU grep
のみ)grep -E
。
egrep 'foo|bar' *.txt
(代替がより大きな正規表現の一部でない限り、括弧は不要です。)
正規表現が必要ない場合は、次のように、複数の-eパラメータを指定してfgrep
またはgrep -F
を使用する方がはるかに高速です。
fgrep -efoo -ebar *.txt
fgrep
(またはgrep -F
)は、正規表現ではなく固定文字列を検索するため、通常のgrepよりもはるかに高速です。
以下のコマンドを試して結果を得ることができます:
egrep 'rose.*Lotus|lotus.*rose' some_file
パイプ(|
)は特殊なシェル文字であるため、エスケープする(\|
)か、マニュアルに従って引用する( man bash
):
引用は、シェルに対して特定の文字または単語の特別な意味を削除するために使用されます。これを使用して、特殊文字の特別な扱いを無効にし、予約語がそのように認識されないようにし、パラメータの展開を防ぐことができます。
二重引用符で文字を囲むと、引用符内のすべての文字のリテラル値が保持されます
引用符で囲まれていないバックスラッシュ(
\
)はエスケープ文字です。
次にいくつかの例を示します(まだ言及されていないツールを使用)。
ripgrep
を使用:
rg "foo|bar" *.txt
rg -e foo -e bar *.txt
git grep
を使用:
git grep --no-index -e foo --or -e bar
注:--and
、--or
、--not
などのブール式もサポートしています。
行ごとのAND演算については、次を参照してください。 複数のANDパターンを使用してgrepを実行する方法
ファイルごとのAND演算については、次を参照してください。 ファイルに存在する複数の文字列または正規表現をすべて確認する方法
複数のパターンをgrepする安価で陽気な方法:
$ echo "foo" > ewq ; echo "bar" >> ewq ; grep -H -f ewq *.txt ; rm ewq
日付が愚かにフォーマットされたアクセスログがありました:[30/Jun/2013:08:00:45 +0200]
しかし、私はそれを次のように表示する必要がありました:30/Jun/2013 08:00:45
問題は、grepステートメントで「OR」を使用すると、2つの別々の行で2つの一致式を受け取っていたことです。
これが解決策です:
grep -in myURL_of_interest *access.log | \
grep -Eo '(\b[[:digit:]]{2}/[[:upper:]][[:lower:]]{2}/[[:digit:]]{4}|[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\b)' \
| paste - - -d" " > MyAccess.log
TL; DR:複数のパターンの1つに一致した後でさらに多くのことを実行する場合は、\(pattern1\|pattern2\)
のように囲みます。
例:「date」という名前を含む変数がStringまたはintとして定義されているすべての場所を検索します。 (例: "int cronDate ="または "String textFormattedDateStamp ="):
_cat myfile | grep '\(int\|String\) [a-zA-Z_]*date[a-zA-Z_]* ='
_
_grep -E
_を使用すると、括弧やパイプをエスケープする必要がありません。つまり、grep -E '(int|String) [a-zA-Z_]*date[a-zA-Z_]* ='
これは私のために働く
root@gateway:/home/sshuser# aws ec2 describe-instances --instance-ids i-2db0459d |grep 'STATE\|TAG'
**STATE** 80 stopped
**STATE**REASON Client.UserInitiatedShutdown Client.UserInitiatedShutdown: User initiated shutdown
**TAGS** Name Magento-Testing root@gateway:/home/sshuser#
これには複数の方法があります。
grep 'foo\|bar' *.txt
egrep 'foo|bar' *.txt
find . -maxdepth 1 -type f -name "*.txt" | xargs grep 'foo\|bar'
find . -maxdepth 1 -type f -name "*.txt" | xargs egrep 'foo|bar'
3番目と4番目のオプションは、ファイルでのみgrepを実行し、ディレクトリに.txt
彼らの名前で。
そのため、ユースケースに従って、上記のオプションのいずれかを使用できます。
ありがとう!!
@ geekosaur's answer に追加するには、タブとスペースも含む複数のパターンがある場合、次のコマンドを使用します
grep -E "foo[[:blank:]]|bar[[:blank:]]"
どこ [[:blank:]]
は、スペースまたはタブ文字を表すRE文字クラスです