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_bad
asbad
と$VARIABLE_good
as good
、$CONTENT_to_buy
as to_buy
、$DUMMYVAR_mixed
asmixed
などを割り当てたいです。
このファイルから ""を検索すると、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を一緒に使用できますgrep
。sed
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
-n
s
コマンドフラグと組み合わせると、成功したp
代替結果のみを印刷できます。
GNUの使用grep
:
$ grep -Po '^[^=]*?_\K.*?(?==.*drugs)' < file
bad
mixed
drugs
一つ作りたいなら変える、次のように使用できます。
string=drugs
grep -Po "^[^=]*?_\K.*?(?==.*$string)" < file
ただし$string
、正規表現に特殊文字が含まれている場合(-P
Perl準拠の正規表現を使用する場合)、特殊文字をエスケープする必要があります(たとえば、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