ファイル内のこれ(2つ)を見つけるにはどうすればよいですか?

ファイル内のこれ(2つ)を見つけるにはどうすればよいですか?

「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

1回の操作で両方を検索する方法は?頑張った

$ grep (then|there) x.x

-bash: 予期しない表示 "(") の近くで構文エラーが発生しました。

そして

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

答え1

式を引用符で囲む必要があります。あなたが経験しているエラーは、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

答え2

ちなみに、ほとんどのバージョンには、-Eを使用したgrepであるegrepというコマンドがあります。私は個人的にタイピングが好きです。

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

grep -Eを使うより

答え3

(または少なくとも私は)マニュアルページの正規表現の下に文書化されているものは実際には拡大する正規表現

grepは、「基本」、「拡張」、および「perl」の3つのバージョンの正規表現構文を理解しています。 GNU grep では、基本構文と拡張構文の間で使用できる機能に違いはありません。他の実装では、基本正規表現はそれほど強力ではありません。 次の説明は拡張正規表現に適用されます。その後、基本的な正規表現の違いの概要が続きます。

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

grep "(then|there)" x.x

(マンページから再び):

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

デフォルトの正規表現では、メタ文字?、+、{、|、(および)が特別な意味を失います。代わりに、バックスラッシュバージョン\?、+、{、\|、(および)が使用されます。

したがって、以下を使用することもできます。

grep "then\|there" x.x

この場合、角かっこが重複するためです。

答え4

Bashのエレガントなシンプルさは、膨大なマニュアルページから消えたようです。

上記の優れたソリューションに加えて、チートシートを提供しようとしました。Bashがステートメントを解析して解釈する方法。その後、このロードマップを使用して質問者が提供した例を解析し、期待どおりに機能しない理由を理解するのに役立ちます。


注:Shellスクリプト行を直接使用してください。入力された入力行は最初に歴史的に展開されます。

各 bash 行は最初にトークン化されます。言い換えれば、いわゆると言ってカットします。トークン。 (トークン化は、中括弧、チルダ、パラメータ、コマンド、算術、プロセス、トークン化、ファイル名の拡張など、他のすべての拡張の前に発生します。)

ここで、トークンは、次の特殊メタ文字の1つで区切られた(区切り付き)入力行の一部を表します。

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

echo最初の例には、スペース区切り文字で生成された2つのトークン(および)がありますxyz

2番目の例も同じです。

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


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

エスケープしないと、これらの10個の特殊文字が区切り文字tokenとして使用されます。そのうちのいくつかは他の意味もありますが、とりわけトークンの区切り文字です。


grepが期待するもの

上記の例では、grepには、、grepタグが必要です。stringfilename

この問題に対する最初の試みは次のとおりです。

$grep (次へ | そこ) xx

この例では(、、、)およびはエスケープされていないメタ文字なので、入力を、、、、、および|トークンに分割するために使用されます。 grepは、とを見たいです。grep(then|there)x.xgrepthen|therex.x

問題に対する2番目の試みは次のとおりです。

grep "(その時|そこ)" xx

grep、、、(then|there)で示されていますx.x。 grepをechoに置き換えると、次のようになります。

echo "(あの|そこに)" xx
(その時|そこに) xx

関連情報