変数リストで項目を検索する最良の方法

変数リストで項目を検索する最良の方法

demo.cfg多くの変数を含む「」というファイルがあります。

$VARIABLE_good="milk bread butter water"
$VARIABLE_bad="beer drugs"
$CONTENT_to_buy="Towel mouse bottle glass pen earphones"
$DUMMYVAR_mixed="drugs water bottle glass"

ファイル全体で「drugs」項目を検索し、その項目が属する項目を識別したいと思います$VARIABLE_bad

$VARIABLE_badasbad$VARIABLE_goodas good$CONTENT_to_buyas to_buy$DUMMYVAR_mixedasmixedなどを割り当てたいです。

このファイルから ""を検索すると、drugs必要な出力は次のようになります。

mixed
bad

将来的には上記の変数が増える可能性があるため、この問題を解決するための柔軟な方法が必要です。

私は試した:

. demo.cfg "drugs"(これを行うと、すべての変数がエクスポートされます)

if [[ $(echo $DUMMYVAR_mixed | grep "drugs") ]]; then echo "mixed"; fi
if [[ $(echo $DUMMYVAR_to_buy | grep "drugs") ]]; then echo "to_buy"; fi
if [[ $(echo $VARIABLE_bad | grep "drugs") ]]; then echo "bad"; fi
if [[ $(echo $VARIABLE_good | grep "drugs") ]]; then echo "good"; fi

しかし、これは冗長に見え、それほど柔軟には見えません。より良い解決策はありますか?

答え1

これは、行に1つしかない小さな場合awkにのみ必要です。=

awk -vpat=drugs -F= '$2 ~ pat {gsub(/^\$[A-Z]+_/, "", $1); print $1; }' demo.cfg

-vpat=...一致に使用する変数を区切り、2番目のフィールドのフィールドと一致させ、最初のフィールドの最初の-F=部分を空の文字列に置き換えます。次に、最初のフィールドを印刷します。 (最初の部分の下線の前には大文字のみがあると仮定します。)=$2 ~gsub$1


値に等号を含めることができる場合は、次のように、等号の後にキーワードが続く行全体を検索できます。

awk -vpat=drugs -F= '$0 ~ ("=.*" pat) {gsub(/^\$[A-Z]+_/, "", $1); print $1; }' demo.cfg

あるいは、2つの部分を手動で分割すると、時間が少し長くなります。


demo.cfgなどのドル記号を持つ割り当てを含めると、シェルは$VARIABLE_good="milk bread butter water"その割り当てを取得できません。

$ . demo.cfg
-bash: =milk bread butter water: command not found

割り当てには変数名のみが使用され、ドル記号は変数拡張時にのみ使用されます。

答え2

これがすべての変数の外観であれば、次のようにsumを一緒に使用できますgrepsed

cat demo.cfg 
$VARIABLE_good="milk bread butter water"
$VARIABLE_bad="beer drugs"
$CONTENT_to_buy="Towel mouse bottle glass pen earphones"
$DUMMYVAR_mixed="drugs water bottle glass"


grep drugs demo.cfg | sed -r 's/.*_([a-z].*)=.*/\1/'
bad
mixed

最初のgrepは単語を検索し、drugs次の式を使用して行をパイプします。sed

.*_=は、最初の下線の前にあるすべての文字を削除します。
([a-z].*)== = 記号まで小文字を保存
.*= 残りの文字列を削除
\1= 保存した式に置き換える

答え3

ここでは以下を使用しますsed

$ sed -n 's/^$[^_=]*_\([^=]*\)=.*drugs.*/\1/p' < file
bad
mixed

-nsコマンドフラグと組み合わせると、成功したp代替結果のみを印刷できます。

GNUの使用grep:

$ grep -Po '^[^=]*?_\K.*?(?==.*drugs)' < file
bad
mixed

drugs一つ作りたいなら変える、次のように使用できます。

string=drugs
grep -Po "^[^=]*?_\K.*?(?==.*$string)" < file

ただし$string、正規表現に特殊文字が含まれている場合(-PPerl準拠の正規表現を使用する場合)、特殊文字をエスケープする必要があります(たとえば、withは以下をstring="..."含むのではなく、少なくとも3文字を含む値と一致します)。 )を含みます...。同等の状況はさらに悪いです。エスケープに失敗するとコマンドインジェクションの脆弱性が発生するsedためです(コンテンツが完全に制御されていない場合)。awk$string

これにより、awk次のことができます。

export STRING=drugs
awk -F = '(n = index($0, "=")) && \
          (m = index($0, "_")) < n && \
          index(substr($0, n+1), ENVIRON["STRING"]) {
            print substr($0, m + 1, n - m - 1)
          }' < file

関連情報