bash 将键=值对解析为变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29108949/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Parse out key=value pairs into variables
提问by Barry
I have a bunch of different kinds of files I need to look at periodically, and what they have in common is that the lines have a bunch of key=value
type strings. So something like:
我有一堆不同类型的文件需要定期查看,它们的共同点是这些行都有一堆key=value
类型字符串。所以像:
Version=2 Len=17 Hello Var=Howdy Other
I would like to be able to reference the names directly from awk... so something like:
我希望能够直接从 awk 引用名称......所以像:
cat some_file | ... | awk '{print Var, }' # prints Howdy Other
How can I go about doing that?
我该怎么做呢?
回答by Wintermute
The closest you can get is to parse the variables into an associative array first thing every line. That is to say,
你能得到的最接近的是在每一行的第一件事中将变量解析成一个关联数组。也就是说,
awk '{ delete vars; for(i = 1; i <= NF; ++i) { n = index($i, "="); if(n) { vars[substr($i, 1, n - 1)] = substr($i, n + 1) } } Var = vars["Var"] } { print Var, }'
More readably:
更易读:
{
delete vars; # clean up previous variable values
for(i = 1; i <= NF; ++i) { # walk through fields
n = index($i, "="); # search for =
if(n) { # if there is one:
# remember value by name. The reason I use
# substr over split is the possibility of
# something like Var=foo=bar=baz (that will
# be parsed into a variable Var with the
# value "foo=bar=baz" this way).
vars[substr($i, 1, n - 1)] = substr($i, n + 1)
}
}
# if you know precisely what variable names you expect to get, you can
# assign to them here:
Var = vars["Var"]
Version = vars["Version"]
Len = vars["Len"]
}
{
print Var, # then use them in the rest of the code
}
回答by John1024
$ cat file | sed -r 's/[[:alnum:]]+=/\n&/g' | awk -F= '=="Var"{print }'
Howdy Other
Or, avoiding the useless use of cat:
或者,避免无用的使用 cat:
$ sed -r 's/[[:alnum:]]+=/\n&/g' file | awk -F= '=="Var"{print }'
Howdy Other
How it works
这个怎么运作
sed -r 's/[[:alnum:]]+=/\n&/g'
This places each key,value pair on its own line.
awk -F= '$1=="Var"{print $2}'
This reads the key-value pairs. Since the field separator is chosen to be
=
, the key ends up as field 1 and the value as field 2. Thus, we just look for lines whose first field isVar
and print the corresponding value.
sed -r 's/[[:alnum:]]+=/\n&/g'
这会将每个键值对放在自己的行上。
awk -F= '$1=="Var"{print $2}'
这将读取键值对。由于字段分隔符被选择为
=
,因此键最终为字段 1,值为字段 2。因此,我们只需查找第一个字段为的行Var
并打印相应的值。
回答by Charles Duffy
Since discussion in commentary has made it clear that a pure-bash solution would also be acceptable:
由于评论中的讨论清楚地表明纯 bash 解决方案也是可以接受的:
#!/bin/bash
# ^-- must be /bin/bash, not /bin/sh
#
# ...must also be bash 4.0 or newer.
while read -r -a words; do # iterate over lines of input
declare -A vars=( ) # refresh variables for each line
set -- "${words[@]}" # update positional parameters
for word; do
if [[ $word = *"="* ]]; then # if a word contains an "="...
vars[${word%%=*}]=${word#*=} # ...then set it as an associative-array key
fi
done
echo "${vars[Var]} " # Here, we use content read from that line.
done <<<"Version=2 Len=17 Hello Var=Howdy Other"
The <<<"Input Here"
could also be <file.txt
, in which case lines in the file would be iterated over.
该<<<"Input Here"
也可以是<file.txt
,在该文件的情况下,行会遍历。
If you wanted to use $Var
instead of ${vars[Var]}
, then substitute printf -v "${word%%=*}" %s "${word*=}"
in place of vars[${word%%=*}]=${word#*=}
, and remove references to vars
elsewhere. Note that this doesn't allow for a good way to clean up variables between lines of input, as the associative-array approach does.
如果您想使用$Var
代替${vars[Var]}
,则用printf -v "${word%%=*}" %s "${word*=}"
代替vars[${word%%=*}]=${word#*=}
,并删除对vars
其他地方的引用。请注意,这不允许像关联数组方法那样清理输入行之间的变量的好方法。
回答by kvantour
I will try to explain you a very generic way to do this which you can adapt easily if you want to print out other stuff.
我将尝试向您解释一种非常通用的方法来执行此操作,如果您想打印其他内容,您可以轻松适应。
Assume you have a string which has a format like this:
假设您有一个格式如下的字符串:
key1=value1 key2=value2 key3=value3
or more generic
或更通用
key1_fs2_value1_fs1_key2_fs2_value2_fs1_key3_fs2_value3
With fs1
and fs2
two different field separators.
随着fs1
与fs2
两个不同的字段分隔符。
You would like to make a selection or some operations with these values. To do this, the easiest is to store these in an associative array:
您想使用这些值进行选择或某些操作。为此,最简单的方法是将它们存储在关联数组中:
array["key1"] => value1
array["key2"] => value2
array["key3"] => value3
array["key1","full"] => "key1=value1"
array["key2","full"] => "key2=value2"
array["key3","full"] => "key3=value3"
This can be done with the following function in awk:
这可以通过 awk 中的以下函数来完成:
function str2map(str,fs1,fs2,map, n,tmp) {
n=split(str,map,fs1)
for (;n>0;n--) {
split(map[n],tmp,fs2);
map[tmp[1]]=tmp[2]; map[tmp[1],"full"]=map[n]
delete map[n]
}
}
So, after processing the string, you have the full flexibility to do operations in any way you like:
因此,在处理完字符串后,您可以完全灵活地以您喜欢的任何方式进行操作:
awk '
function str2map(str,fs1,fs2,map, n,tmp) {
n=split(str,map,fs1)
for (;n>0;n--) {
split(map[n],tmp,fs2);
map[tmp[1]]=tmp[2]; map[tmp[1],"full"]=map[n]
delete map[n]
}
}
{ str2map((map["Version"] < 3) { print map["var"]/map["Len"] }
," ","=",map) }
{ print map["Var","full"] }
' file
The advantage of this method is that you can easily adapt your code to print any other key you are interested in, or even make selections based on this, example:
这种方法的优点是您可以轻松调整代码以打印您感兴趣的任何其他键,甚至可以根据此进行选择,例如:
change="foo=red bar=green baz=blue"
#use below if var is in CSV (instead of space as delim)
change=`echo $change | tr ',' ' '`
for change in $changes; do
set -- `echo $change | tr '=' ' '`
echo "variable name == and variable value == "
#can assign value to a variable like below
eval my_var_=;
done
回答by prash
I know this is particularly regarding awk but mentioning this as many people come here for solutions to break down name = value pairs ( with / without using awk as such).
我知道这尤其与 awk 有关,但提到这一点是因为很多人来这里寻求解决方案来分解名称 = 值对(使用 / 不使用 awk 等)。
I found below way simple straight forward and very effective in managing multiple spaces / commas as well -
我发现以下方法简单直接,并且在管理多个空格/逗号方面也非常有效 -
Source: http://jayconrod.com/posts/35/parsing-keyvalue-pairs-in-bash
来源:http: //jayconrod.com/posts/35/parsing-keyvalue-pairs-in-bash
##代码##