我有一个名为“”的文件,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
这只是需要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
-n
s
与命令的标志结合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