web-dev-qa-db-ja.com

ファイルでこれまたはそれ(2つ)をgrepするにはどうすればよいですか?

「then」と「there」があるファイルがあります。

できます

$ grep "then " x.x
x and then some
x and then some
x and then some
x and then some

そして私はできる

$ grep "there " x.x
If there is no blob none some will be created

一度に両方を検索するにはどうすればよいですか?私は試した

$ grep (then|there) x.x

-bash:予期しないトークン `( 'に近い構文エラー

そして

grep "(then|there)" x.x
durrantm.../code
# (Nothing)
44
Michael Durrant

式を引用符で囲む必要があります。受け取ったエラーは、bashが(を特殊文字として解釈した結果です。

また、拡張正規表現を使用するようにgrepに指示する必要があります。

$ grep -E '(then|there)' x.x

拡張正規表現がない場合は、|(、および)をエスケープする必要があります。ここでは単一引用符を使用していることに注意してください。 Bashは、二重引用符内のバックスラッシュを特別に扱います。

$ grep '\(then\|there\)' x.x

この場合、グループ化は必要ありません。

$ grep 'then\|there' x.x

次のようなものが必要です。

$ grep 'the\(n\|re\)' x.x
60
user26112

簡単な補足として、ほとんどのフレーバーにはegrepと呼ばれるコマンドがあり、これは単に-Eを付けたgrepです。私は個人的にタイプする方がずっと好きです

egrep "i(Pod|Pad|Phone)" access.log

Grep -Eを使用するより

7
Trausti Thor

(または少なくとも私の)manページのREGULAR EXPRESSIONSで文書化されているものは、実際にはextendedregexps用です。

grepは、「基本」、「拡張」、「Perl」の3つの異なるバージョンの正規表現構文を理解します。 GNU grepでは、基本構文と拡張構文で使用可能な機能に違いはありません。他の実装では、基本正規表現はそれほど強力ではありません。次の説明は拡張正規表現に適用されます。基本正規表現の違いは後でまとめられます。

しかし、grepはデフォルトでそれらを使用しません--Eスイッチが必要です:

grep "(then|there)" x.x

なぜなら(再びmanページから):

基本正規表現と拡張正規表現

基本的な正規表現では、メタ文字?、+、{、|、(、および)は特別な意味を失います。代わりに、円記号バージョンの\?、+、{、\ |、(、および)を使用します。

だからあなたも使うことができます:

grep "then\|there" x.x

この場合、括弧は不必要です。

2
goldilocks

Bashのエレガントなシンプルさは、巨大なmanページで失われているようです。

上記の優れたソリューションに加えて、bashがステートメントを解析および解釈する方法に関するチートシートを提供しようと思います。次に、このロードマップを使用して、質問者が提示した例を解析して、意図したとおりに機能しない理由をよりよく理解できるようにします。


注:シェルスクリプトの行は直接使用されます。入力された入力行は最初に履歴が展開されます。

各bash行は最初にトークン化されます、つまり、いわゆるトークンに切り刻まれます。 (トークン化は、ブレース、チルド、パラメーター、コマンド、算術、プロセス、ワード分割、およびファイル名の拡張を含む、他のすべての拡張の前に発生します。)

ここでのトークンは、次の特別なメタ文字のいずれかで区切られた(区切られた)入力行の一部を意味します。

space,  - White space...
tab, 
newline,

‘<’,    - Redirection & piping...
‘|’, 
‘>’
‘&’,    - And/Both < | > | >>  .or.  &<file descriptor>

‘;’,    - Command termination

‘(’,    - Subshell, closed by -     ‘)’

Bashは他の多くの特殊文字を使用しますが、これらの10文字だけが初期トークンを生成します。

ただし、これらのメタ文字もトークン内で使用する必要がある場合があるため、それらの特別な意味を取り除く方法が必要です。これはエスケープと呼ばれます。エスケープは、1つ以上の文字の文字列を引用することによって(つまり、'xx..'"xx..")、または個々の文字の前にバックスラッシュを付けることによって(つまり、\x)行われます。 (引用符も引用符で囲む必要があるため、また二重引用符ですべてが引用されるわけではないため、これよりも少し複雑ですが、今のところはこの簡略化で十分です。)

他の言語のように、bashの引用とテキストの文字列を引用するという考えを混同しないでください。 bashの引用符の間にあるのは文字列ではなく、トークンを区切らないようにメタ文字がエスケープされている入力行のセクションです

'"の間には重要な違いがありますが、それは別の日です。

残りのエスケープされていないメタ文字は、トークンセパレータになります。

たとえば

$ echo "x"'y'\g
xyg

$ echo "<"'|'\>
<|>

$ echo x\; echo y
x; echo y

最初の例では、スペース区切り文字によって生成された2つのトークン、echoxyzがあります。

2番目の例でも同様です。

3番目の例では、セミコロンがエスケープされているため、スペース区切り文字echox;echo、およびyによって生成される4つのトークンがあります。次に、最初のトークンがコマンドとして実行され、次の3つのトークンを入力として受け取ります。 2番目のechoは実行されないことに注意してください。


覚えておくべき重要なことは、bashが最初にエスケープ文字('"、および\)を探し、次にエスケープされていないメタ文字区切り文字をこの順番で探すということです。

エスケープされていない場合、これらの10個の特殊文字はtoken区切り文字として機能します。それらの一部には追加の意味もありますが、何よりもまず、それらはトークン区切り文字です。


grepが期待するもの

上記の例では、grepはこれらのトークン、grepstringfilenameを必要とします。

質問の最初の試みは:

$ grep(then | there)x.x

この場合、()および|はエスケープされていないメタ文字であるため、入力をこれらのトークンに分割するのに役立ちます:grep(then|there)x.x。 grepはgrepthen|there、およびx.xを表示したいと考えています。

質問の2番目の試みは次のとおりです。

grep "(then | there)" x.x

これはgrep(then|there)x.xにトークン化します。これは、grepをechoに置き換えると確認できます。

echo "(then | there)" x.x
(当時|そこ)x.x

0
Elliptical view