从变量列表中查找项目的最佳方法

从变量列表中查找项目的最佳方法

我有一个名为“”的文件,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

这只是需要awk.=线路上只有一个的小情况:

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

-vpat=...设置匹配中使用的变量:分隔,匹配第二个字段上-F=的字段,并用空字符串替换第一个字段的初始部分。然后打印第一个字段。 (我假设初始部分下划线之前只有大写字母。)=$2 ~gsub$1


如果值中可以有等号,我们可以在整行中搜索等号后跟关键字,如下所示:

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

或者直接手动分割两部分,但这会有点长。


请注意,如果demo.cfg包含诸如$VARIABLE_good="milk bread butter water", 之类的带有美元符号的分配,则在 shell 中获取它将不起作用:

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

赋值仅采用变量的名称,美元符号仅在扩展变量时使用。

答案2

如果这就是所有变量的样子,您可以像这样一起使用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

-ns与命令的标志结合p允许仅打印成功替换的结果。

使用 GNU grep

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

如果你想做drugs一个多变的,那么你可以使用:

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

但请注意,如果$string在正则表达式中包含特殊字符,在这种情况下(使用-P),Perl 兼容的正则表达式,那么它们必须被转义(例如, withstring="..."将匹配包含至少 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

相关内容