文字列がBashのファイルに存在するかどうかをテストするにはどうすればよいですか?


337

ディレクトリ名を含むファイルがあります。

my_list.txt

/tmp
/var/tmp

その名前がファイルに既に存在する場合、ディレクトリ名を追加する前にBashをチェックインしたいと思います。


ファイル内のすべての文字列を検索するには、FORループでgrepを実行します。unix.stackexchange.com
Noam Manos

回答:


654
grep -Fxq "$FILENAME" my_list.txt

終了ステータスは、名前が見つかった場合は0(true)、見つからなかった場合は1(false)なので、次のようになります。

if grep -Fxq "$FILENAME" my_list.txt
then
    # code if found
else
    # code if not found
fi

説明

以下は、manページのgrep関連セクションです

grep [options] PATTERN [FILE...]

-F--fixed-strings

        PATTERNを、一致する改行で区切られた固定文字列のリストとして解釈します。

-x--line-regexp

        行全体と完全に一致する一致のみを選択します。

-q--quiet--silent

        静か; 標準出力には何も書き込みません。エラーが検出された場合でも、一致するものが見つかった場合は、ステータスがゼロですぐに終了します。-sまたは--no-messagesオプションも参照してください。

エラー処理

コメントで正しく指摘されているように、上記のアプローチは、文字列が見つかった場合と同様にエラーケースを静かに扱います。エラーを別の方法で処理する場合は、-qオプションを省略し、終了ステータスに基づいてエラーを検出する必要があります。

通常、終了ステータスは、選択された行が見つかった場合は0、それ以外の場合は1です。ただし、-qor --quietまたはor --silentオプションが使用され、選択された行が見つかった場合を除き、エラーが発生した場合の終了ステータスは2です。ただし、そのようなプログラムのためのPOSIXだけ義務付け、grepcmp、およびdiff、エラーの場合に終了ステータスが1より大きいこと。したがって、移植性のために、2との厳密な等価ではなく、この一般的な条件をテストするロジックを使用することをお勧めします。

からの通常の出力を抑制するために、にgrepリダイレクトできます/dev/null。標準エラーは無向のままであるため、grep印刷される可能性のあるエラーメッセージは、おそらく望むとおりにコンソールに表示されることに注意してください。

3つのケースを処理するには、caseステートメントを使用できます。

case `grep -Fx "$FILENAME" "$LIST" >/dev/null; echo $?` in
  0)
    # code if found
    ;;
  1)
    # code if not found
    ;;
  *)
    # code if an error occurred
    ;;
esac

2
このコマンドをbashスクリプトから実行すると、0または1を変数にキャッチする方法は?
Toren

6
@Toren最新の終了ステータスには、を使用してアクセスできます$?ifステートメントと一緒にgrepコマンドを使用することもできます(更新された回答に示されています)。
Shawn Chin

5
使用できgrep -Fqx "$FILENAME"、変数の内容に含まれる正規表現の文字について心配する必要はありません。また、検索文字列でそれらを使用する必要もありません。
追って通知があるまで一時停止。

4
この答えを見ている人のためのいくつかの注意事項:1)bashでは、0は常にtrueであり、それ以外は常にfalseです。2)-xフラグは、行全体を正確に一致させる場合にのみ使用してください。文字列がファイルに存在するかどうかを確認するだけの場合は、オフのままにします。文字列が正確に存在するが、必ずしも行全体に一致しない(つまり、単語全体として)かどうかを確認するには、-wを使用します。
Schmick 2017年

1
私はgetheしていない-q / --silentことが必要なのですか?エラーが発生した場合でも、bashを「すべて良い」と誤って言います。私がそれを正しく得たなら。この場合、欠陥のある概念のようです。
redanimalwar

90

次の解決策について:

grep -Fxq "$FILENAME" my_list.txt

(私がしたように)-Fxq平易な英語で何が意味するのか疑問に思われる場合:

  • F:PATTERNの解釈方法に影響します(正規表現の代わりに固定文字列)
  • x:行全体に一致
  • q:Shhhhh ...最小限の印刷

manファイルから:

-F, --fixed-strings
    Interpret  PATTERN  as  a  list of fixed strings, separated by newlines, any of which is to be matched.
    (-F is specified by POSIX.)
-x, --line-regexp
    Select only those matches that exactly match the whole line.  (-x is specified by POSIX.)
-q, --quiet, --silent
    Quiet; do not write anything to standard output.  Exit immediately with zero status  if  any  match  is
          found,  even  if  an error was detected.  Also see the -s or --no-messages option.  (-q is specified by
          POSIX.)

5
-Fはファイルの処理には影響しません。PATTERNの解釈方法に影響します。通常、PATTERNは正規表現として解釈されますが、-Fを指定すると、固定文字列として解釈されます。
Adam S

41

私の心の3つの方法:

1)パス内の名前の簡単なテスト(これがあなたのケースであるかどうかはわかりません)

ls -a "path" | grep "name"


2)ファイル内の文字列の短いテスト

grep -R "string" "filepath"


3)正規表現を使用したより長いbashスクリプト:

#!/bin/bash

declare file="content.txt"
declare regex="\s+string\s+"

declare file_content=$( cat "${file}" )
if [[ " $file_content " =~ $regex ]] # please note the space before and after the file content
    then
        echo "found"
    else
        echo "not found"
fi

exit

ループを使用してファイルコンテンツで複数の文字列をテストする必要がある場合、たとえば、任意のcicleで正規表現を変更する場合、これはより速くなるはずです。


10
$ file_contenetの前後にスペースが必要なのはなぜですか?
EminezArtus

プラス1は、高速なソリューションとより一般的なソリューション
Wassadamo

19

より簡単な方法:

if grep "$filename" my_list.txt > /dev/null
then
   ... found
else
   ... not found
fi

ヒント:/dev/nullコマンドの終了ステータスが必要な場合に送信しますが、出力は必要ありません。


1
または:) -qと同じように使用します--quiet
rogerdpack

-qここでもベストアンサーに同意し、4位です。この世界では正義はありません。
tatsu

14

最も簡単で簡単な方法は次のとおりです。

isInFile=$(cat file.txt | grep -c "string")


if [ $isInFile -eq 0 ]; then
   #string not contained in file
else
   #string is in file at least once
fi

grep -cは、ファイル内で文字列が発生した回数を返します。


5

私があなたの質問を正しく理解していれば、これはあなたが必要としていることをするはずです。

  1. $ check変数を使用して、追加するディレクトリを指定できます
  2. ディレクトリがすでにリストにある場合、出力は「dir alreadyリスト」です。
  3. ディレクトリがまだリストにない場合は、my_list.txtに追加されます

一行でcheck="/tmp/newdirectory"; [[ -n $(grep "^$check\$" my_list.txt) ]] && echo "dir already listed" || echo "$check" >> my_list.txt


grepの出力をテストする必要はありません。Thomasが答えたgrep -qように、grepを直接使用して直接呼び出すことができifます。さらに、質問には、リストに追加する前にディレクトリが存在するかどうかの確認は含まれていませんでした(結局、削除されたディレクトリのリストである可能性があります)。
sorpigal

サンプルスクリプトを削除しましたが、トーマスの答えに何も追加されませんでした。
lecodesportif 2011年

3

1行の存在を確認するだけの場合は、ファイルを作成する必要はありません。例えば、

if grep -xq "LINE_TO_BE_MATCHED" FILE_TO_LOOK_IN ; then
  # code for if it exists
else
  # code for if it does not exist
fi  

3

fgrepを使用した私のバージョン

  FOUND=`fgrep -c "FOUND" $VALIDATION_FILE`
  if [ $FOUND -eq 0 ]; then
    echo "Not able to find"
  else
    echo "able to find"     
  fi  

-cオプションが表示されないfgrep --help
Nam G VU


1

@Thomasのソリューションは何らかの理由で機能しませんでしたが、特殊文字と空白を含む長い文字列があったため、次のようにパラメーターを変更しました。

if grep -Fxq 'string you want to find' "/path/to/file"; then
    echo "Found"
else
    echo "Not found"
fi

それが誰かを助けることを願って


0

grepなしのソリューションは私にとってはうまくいきます:

MY_LIST=$( cat /path/to/my_list.txt )



if [[ "${MY_LIST}" == *"${NEW_DIRECTORY_NAME}"* ]]; then
  echo "It's there!"
else
echo "its not there"
fi

に基づいて:https : //stackoverflow.com/a/229606/3306354


1
ファイルが大きい場合、メモリを使いすぎます。 受け入れられた回答にgrep -q記載されているのが最も効率的なアプローチです。
codeforester 2018年

0
grep -Fxq "String to be found" | ls -a
  • grepは内容を確認するのに役立ちます
  • lsはすべてのファイルを一覧表示します

ls標準入力を受け入れないと思いますか?
Thom Wiggers

@ThomWiggers私も同じことを試しましたが、うまくいきました。
Shinoy Shaji

-1
if grep -q "$Filename$" my_list.txt
   then
     echo "exist"
else 
     echo "not exist"
fi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.