grepはtrue / falseを返すことができますか、代替方法があります


130

このスクリプトの一部として、指定された最初の引数がファイルの最初の単語と一致するかどうかを確認できる必要があります。存在する場合は、エラーメッセージで終了します。そうでない場合は、引数をファイルに追加します。ifステートメントの記述方法は理解していgrepますが、スクリプト内での使用方法は理解していません。私はそれgrepがこのようなものになることを理解しています

grep ^$1 schemas.txt

これは私が作っているよりもずっと簡単だと思う。

ifステートメントで「引数が多すぎます」というエラーが表示されます。私はその間のスペースを取り除いたgrep -q後、期待されるエラー二項演算子を得ました。

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi

1
失う[]そしてそれは働くでしょう。あなたはおそらくあなたのパターンを引用したいのですが:if grep -q "^$1" schemas.txt; then …
derobert

:バッシュの「グループコマンド」機能を使用して1つのラインソリューションstackoverflow.com/questions/6550484/...
トレバー・ボイド・スミス

回答:


186

grep何か(ゼロ)が見つかった場合と、何も見つからなかった場合(ゼロ以外)に、異なる終了コードを返します。でif声明、ゼロの終了コードが「真」にマップされ、ゼロ以外の終了コードがfalseにマッピングされています。さらに、grepには-q、一致したテキストを出力しない(ただし、終了ステータスコードのみを返す)引数があります

したがって、次のようにgrepを使用できます。

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

簡単なメモとして、のようなif [ -z "$var" ]…ことをする[と、実際にはgrepのように実行しているコマンドであることがわかります。私のシステムでは、/usr/bin/[です。(まあ、技術的には、おそらくシェルに組み込まれていますが、それは最適化です。コマンドのように動作します)。同じように機能し、[trueの場合はゼロの終了コード、falseの場合はゼロ以外の終了コードを返します。(終了を除いてtest、と同じものです)[]


if文に括弧が必要ないのはなぜですか?私はそれがなくても動作しますが、理由がわかりません。ブラケットなしでネストすることはできますか?
ローレン

@Laurenは簡単なメモを逃しましたか?[、それだけではgrepのように、(概念的には)あなたが実行しているコマンドのif構文の一部ではありません
derobert

2
@Lauren [の内部ではgrepを使用しません。チェックする条件に応じて、どちらか一方を使用します。(if、btw、終了コードをチェックするだけで、任意のコマンドを使用できます。)…まあ、おそらくgrepを[内で使用する理由を考え出すことができると思いますが、それはかなり複雑なスクリプトであり、普通のことではありません。
デロバート

3
参考までに、実行ls -l /usr/bin/\[man [[、それが他のプログラムと同じであることがわかります。これは構文要素のように見えます。これにより、わかりやすくわかりやすくなります。(便宜上、[bash、dash、その他にも組み込まれていますが、それでもコマンドです)。type -all [bash でも試してください。
cas

1
@AlexanderCskaは、grepが一致した行を出力する(たとえば、どこかにパイプする)場合、-qgrepにquiet(一致した行を出力しない)を指示する場合、省略します。
デロバート

48

別の簡単な方法はを使用することgrep -cです。

出力(終了コードとして返されない)、パターンに一致する行の数、したがって、一致しない場合は0、一致する場合は1以上。

したがって、パターンが3回以上一致することを確認する場合は、次のようにします。

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...

17
より正確には、1回だけ見つかった場合は1 を出力します。見つかった一致の量に関係なく1を出力するには、grep -cim1代わりに使用します。
マナトワーク

このメソッドは、grepエラーとgrep 'pattern found 0 times'を区別するためにも使用できます。(正確なifステートメントを使用していませんが、変数が必要だと思います)
Evan Benn

3

私はこれに遅れていることを知っていますが、この短いバージョンが大好きです:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt

0

ファイルの最初の単語をキャッチしたい場合は-zw、grepに追加する必要があります

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

行なし-zで最初の単語を取得します。なければ-w、私たちは単語の一部を取得します。


-2

角括弧で使用したい場合は、以下を実行できます

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

このロジックはすべてのコマンドに対して機能します。コマンドをバックティック内に配置するだけです(タブの上のボタン、Escボタンの下、または1ボタンの左)。


1
を引用符で囲む必要があります`grep -q PATTERN file.txt`。そうしないと、split + glob演算子が適用され、の文字$IFSまたはワイルドカード文字を含む出力で問題が発生します。より一般的に[ "`cmd`" ]cmd、stdoutに空でない行を少なくとも1つ出力するとtrueを返します(NULバイトを出力すると潜在的な問題が発生します)。つまり、シェルは出力全体をメモリに保存し、終了するまで待機する必要があります。if cmd | grep -q .その点で、代わりに使用することが望ましい場合があります。
ステファンシャゼル

このコマンドはまったく意味がありません。-qスイッチの目的は、の出力を抑制 することgrepです。あなたは言っています:file.txtでPATTERNを確認し、出力を抑制してから、PATTERNが見つかったかどうかに従って戻りステータスを設定します。次に、戻りステータスを無視し、コマンド出力(空にしました)を取得し、単語分割とファイルグロブ展開を適用して(引数なしになります)、正確に1つの引数で[(別名test)コマンドを実行します-つまり、]そして、それはエラーになるので、「not found」をエコーし​​ます。@StéphaneChazelas、私は何かを見逃しましたか?
ワイルドカード

1
@Wildcard、あなたは正しいです、私はどうやら見落としていました-q。そのコメントはにとって意味が[ `grep PATTERN file.txt ` ]ありますが、コメントで示唆されているように、[ "`grep -n PATTERN file.txt`" ]PATTERNが空の行のみに一致する場合はより良いでしょう。もちろんここはif grep -q PATTERN file.txtあなたが望むものですが。
ステファンシャゼラス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.