次の2つのファイルがあるとしましょう。
$ cat search_file.txt
This line contains kwd1.
This line contains kwd2.
This line contains no match.
This line contains no match.
This line contains kwd5.
$ cat search_kwd.sh
grep kwd1 search_file.txt
grep kwd2 search_file.txt
grep kwd3 search_file.txt
grep kwd4 search_file.txt
grep kwd5 search_file.txt
search_kwd.sh を実行すると、次の結果が表示されます。
$ sh search_kwd.sh
This line contains kwd1.
This line contains kwd2.
This line contains kwd5.
string
grepが一致するものを見つけることができないときはいつでも印刷したいと思います。出力は次のとおりです。
$ sh search_kwd.sh
This line contains kwd1.
This line contains kwd2.
string
string
This line contains kwd5.
Bashでどうすればいいですか?
答え1
grep
何も見つからない場合は、ゼロ以外のコードで終了します。
からman grep
:
通常、終了状態は、行が選択されている場合は0、行が選択されていない場合は1、エラーが発生した場合は2です。
したがって、次のものを使用できます。
grep kwd3 search_file.txt || echo "string"
答え2
@RoVoの回答を拡張するには、forループを使用してすべてのクエリを繰り返すことができます。
for term in "kwd1" "kwd2" "kwd3" "kwd4" "kwd5"; do
grep "$term" search_file.txt || echo "string"`
done
答え3
要求された出力には各入力行に1行の出力があるように見えます。一致する場合はその行をコピーし、それ以外の場合は置き換えます。ファイルを5回読み、次のように印刷するよりも良い方法はありますか? per search_kwd.sh ファイルは、入力ファイルの代わりに入力ファイルで見つかった順序で行をリストします。
代わりに、入力ファイルを一度に1行ずつ処理する必要があります。これを行うには多くのツールがあります。例えば
#!/bin/sh
sed -e '/kwd1/{p;d}
/kwd2/{p;d}
/kwd3/{p;d}
/kwd4/{p;d}
/kwd5/{p;d}
s/.*/string/' search_file.txt
これは、一致するキーワードごとに行を印刷し、それを破棄して次の行に移動することを意味します。すべてのキーワードを見て、一致するものがない場合は、行を文字列に変更します(それから暗黙的に印刷します)。
awk
このようなものを使用できます
#!/bin/sh
awk '{ if (/kwd1|kwd2|kwd3|kwd4|kwd5/) { print } else {print "string" }}' search+file.txt
純粋なシェル実装を持つことができます
#!/bin/sh
while read -r line
do
case "$line" in
(*"kwd1"*|*"kwd2"*|*"kwd3"*|*"kwd4"*|*"kwd5"*) printf '%s\n' "$line" ;;
(*) printf '%s\n' "string" ;;
esac
done < search_file.txt
Perl、Ruby、Pythonも使用できます。