从ini文件中收集两个关键字(变量+字符串)之间的数据(两个参数)
Collect the data (two parameters) between two keywords (variable+string) from ini file
我有一个 txt.ini 文件的内容(我不能修改这个文件的结构):
txt.ini
txt.ini
[person_0:public]
name=john
groups=0,1,2
age=30
[person_0:private]
married=false
weight=190
height=100
[person_1:public]
name=mark
groups=0,4
age=28
[person_1:private]
married=false
weight=173
height=70
[person_2:public]
name=tony
groups=3,4
age=30
[person_3:private]
married=true
weight=202
height=120
我有一个变量“person”,它在循环中取以下值之一:person_0、person_1、person_3,我想收集这个人的数据,比如年龄每个 'person' 一个一个分组。
我的想法是删掉 $person:public 和 $person:private 之间的部分,然后是 collect
例如
设置变量 person=person_1
输出:
组=0,4
年龄=28
我在bash中准备了代码(persons是person_0、person_1、person2的列表):
for person in ${persons[@]}; do
file="txt.ini"
echo "$person"
a=$(awk -v a=$person":private" -v b=$person":public" '/a/{found=0} {if(found) print} /b/{found=1}' $file)
IFS=$'\n' lines=($a)
IFS='=' read grouplist grouplist_values <<< ${lines[1]}
IFS='=' read age age_values <<< ${lines[4]}
echo "Group list = $grouplist_values"
echo "Age = $age_values"
群组列表和年龄为空。输出:
person_0
Group list =
Age =
person_1
Group list =
Age =
person_2
Group list =
Age =
预计:
person_0
Group list =0,1,2
Age =30
person_1
Group list =0,4
Age =28
person_2
Group list =3,4
Age =30
我将在代码的另一部分中“按人”使用此数据。我正在处理具有不同数量“人”的文件。
真不知道怎么回事
我也试过:
#export person="person_0"
#a=$(awk '/ENVIRON["person"]:private/{found=0} {if(found) print} /ENVIRON["person"]:public/{found=1}' $file)
和
private=$person":private"
public=$person":public"
echo "private=$private"
echo "public=$public"
a=$(awk -v a=$private" -v b=$public '/a/{found=0} {if(found) print} /b/{found=1}' $config_file)
但输出是一样的:
person_0
private=person_0:private
public=person_0:public
Group list =
Age =
对我来说奇怪的是 - 当我硬编码切割范围时它工作正常:
a=$(awk '/person_0:private/{found=0} {if(found) print} /person_0:public/{found=1}' $file)
或
a=$(awk '/person_1:private/{found=0} {if(found) print} /person_1:public/{found=1}' $file)
你知道我怎样才能巧妙地收集这些数据吗?
假设:
- 对于给定的人(例如,
person_0
)显示该人以及 groups
和 age
的关联 (public
) 字段
- 没有给出我们应该如何处理这些数据的指示,所以假设,现在,我们只需要打印到标准输出
- 要处理的人员列表在
bash
数组 persons[]
中
- 字符串
:public
和 :private
只出现在块头中
一个 awk
想法,我们使用 split()
函数根据不同的分隔符解析一行:
awk '
FNR==NR { persons[]
next
}
/:private/ { printme=0 }
/:public/ { printme=0
split(,arr,"[]:[]")
person=arr[2]
if (person in persons) {
printme=1
printf "%s%s\n", pfx, person
pfx="\n"
}
}
printme { split(,arr,"=")
if (arr[1] == "groups") print "Group list =" arr[2]
if (arr[1] == "age") print "Age =" arr[2]
}
' <(printf "%s\n" "${persons[@]}") txt.ini
使用多字符输入字段定界符的此主题的变体:
awk -F"[]:=[]" '
FNR==NR { persons[]
next
}
=="private" { printme=0 }
=="public" { printme=0
if ( in persons) {
printme=1
printf "%s%s\n", pfx,
pfx="\n"
}
}
printme && =="groups" { print "Group list =" }
printme && =="age" { print "Age =" }
' <(printf "%s\n" "${persons[@]}") txt.ini
与:
$ typeset -p persons
declare -a persons=([0]="person_0" [1]="person_1" [2]="person_2")
两组awk
代码生成:
person_0
Group list =0,1,2
Age =30
person_1
Group list =0,4
Age =28
person_2
Group list =3,4
Age =30
注意: 这可以变得更加动态(public
and/or private
?不同的领域?)但这将需要更多编码
请您尝试以下操作:
awk -v RS='' ' # split the records on the blank lines
/public/ { # "public" record
split(, a, /[\[:]/); print a[2] # extract the "person_xx" substring
for (i = 2; i <= NF; i++) { # iterate over the lines of the record
split($i, a, /=/)
if (a[1] == "groups") print "Group list =" a[2]
else if (a[1] == "age") print "Age =" a[2]
}
print "" # insert a blank line
}
' txt.ini
输出:
person_0
Group list =0,1,2
Age =30
person_1
Group list =0,4
Age =28
person_2
Group list =3,4
Age =30
- 通过将
awk
变量RS
设置为空字符串,记录是
由空行分隔,字段由换行符分隔
字符。
- 假设所需数据包含在
public
块中,
我们可以一一解析public
记录的字段。
[编辑]
根据 OP 的评论,这里是更新版本:
#!/bin/bash
persons=("person_0") # list of desired person(s)
for person in "${persons[@]}"; do # loop over the bash array
awk -v RS='' -v person="$person" ' # assign awk variables
~ person ":public" { # "public" record of the person
split(, a, /[\[:]/); print a[2] # extract the "person_xx" substring
for (i = 2; i <= NF; i++) { # iterate over the lines of the record
split($i, a, /=/)
if (a[1] == "groups") print "Group list =" a[2]
else if (a[1] == "age") print "Age =" a[2]
}
}
' txt.ini
echo # insert a blank line
done
- 您可以将
persons
数组分配给任何您想要的人。
- 模式
~ person ":public"
测试记录的第一个字段 </code>(例如 <code>[person_0:public]
)是否匹配 awk 变量 person
(通过 -v
选项)后跟字符串“:public”.
显然 awk 脚本多次重复读取 txt.ini
文件
persons
数组中#elements 的倍数。
如果 text.ini
文件很长 and/or 则 persons
数组有很多元素,
循环将是低效的。这是另一个变体:
#!/bin/bash
persons=("person_0" "person_1") # bash array just for an example
awk -v RS='' -v persons_list="${persons[*]}" '
# persons_list is a blank separated list of persons
BEGIN {
split(persons_list, a) # split persons_list back to an array
for (i in a) persons[a[i]] # create a new array indexed by person
}
/public/ { # "public" record
split(, a, /[\[:]/) # extract the "person_xx" substring
if (a[2] in persons) { # if the person exists in the list
print a[2]
for (i = 2; i <= NF; i++) { # iterate over the lines of the record
split($i, a, /=/)
if (a[1] == "groups") print "Group list =" a[2]
else if (a[1] == "age") print "Age =" a[2]
}
print "" # insert a blank line
}
}
' txt.ini
请注意,它假定人物字符串不包含空白字符。
如果是这样,请在将 persons_list
分配给未使用的时更改分隔符
逗号等字符。
我有一个 txt.ini 文件的内容(我不能修改这个文件的结构):
txt.ini
txt.ini
[person_0:public]
name=john
groups=0,1,2
age=30
[person_0:private]
married=false
weight=190
height=100
[person_1:public]
name=mark
groups=0,4
age=28
[person_1:private]
married=false
weight=173
height=70
[person_2:public]
name=tony
groups=3,4
age=30
[person_3:private]
married=true
weight=202
height=120
我有一个变量“person”,它在循环中取以下值之一:person_0、person_1、person_3,我想收集这个人的数据,比如年龄每个 'person' 一个一个分组。
我的想法是删掉 $person:public 和 $person:private 之间的部分,然后是 collect
例如 设置变量 person=person_1 输出: 组=0,4 年龄=28
我在bash中准备了代码(persons是person_0、person_1、person2的列表):
for person in ${persons[@]}; do
file="txt.ini"
echo "$person"
a=$(awk -v a=$person":private" -v b=$person":public" '/a/{found=0} {if(found) print} /b/{found=1}' $file)
IFS=$'\n' lines=($a)
IFS='=' read grouplist grouplist_values <<< ${lines[1]}
IFS='=' read age age_values <<< ${lines[4]}
echo "Group list = $grouplist_values"
echo "Age = $age_values"
群组列表和年龄为空。输出:
person_0
Group list =
Age =
person_1
Group list =
Age =
person_2
Group list =
Age =
预计:
person_0
Group list =0,1,2
Age =30
person_1
Group list =0,4
Age =28
person_2
Group list =3,4
Age =30
我将在代码的另一部分中“按人”使用此数据。我正在处理具有不同数量“人”的文件。
真不知道怎么回事
我也试过:
#export person="person_0"
#a=$(awk '/ENVIRON["person"]:private/{found=0} {if(found) print} /ENVIRON["person"]:public/{found=1}' $file)
和
private=$person":private"
public=$person":public"
echo "private=$private"
echo "public=$public"
a=$(awk -v a=$private" -v b=$public '/a/{found=0} {if(found) print} /b/{found=1}' $config_file)
但输出是一样的:
person_0
private=person_0:private
public=person_0:public
Group list =
Age =
对我来说奇怪的是 - 当我硬编码切割范围时它工作正常:
a=$(awk '/person_0:private/{found=0} {if(found) print} /person_0:public/{found=1}' $file)
或
a=$(awk '/person_1:private/{found=0} {if(found) print} /person_1:public/{found=1}' $file)
你知道我怎样才能巧妙地收集这些数据吗?
假设:
- 对于给定的人(例如,
person_0
)显示该人以及groups
和age
的关联 ( - 没有给出我们应该如何处理这些数据的指示,所以假设,现在,我们只需要打印到标准输出
- 要处理的人员列表在
bash
数组persons[]
中
- 字符串
:public
和:private
只出现在块头中
public
) 字段
一个 awk
想法,我们使用 split()
函数根据不同的分隔符解析一行:
awk '
FNR==NR { persons[]
next
}
/:private/ { printme=0 }
/:public/ { printme=0
split(,arr,"[]:[]")
person=arr[2]
if (person in persons) {
printme=1
printf "%s%s\n", pfx, person
pfx="\n"
}
}
printme { split(,arr,"=")
if (arr[1] == "groups") print "Group list =" arr[2]
if (arr[1] == "age") print "Age =" arr[2]
}
' <(printf "%s\n" "${persons[@]}") txt.ini
使用多字符输入字段定界符的此主题的变体:
awk -F"[]:=[]" '
FNR==NR { persons[]
next
}
=="private" { printme=0 }
=="public" { printme=0
if ( in persons) {
printme=1
printf "%s%s\n", pfx,
pfx="\n"
}
}
printme && =="groups" { print "Group list =" }
printme && =="age" { print "Age =" }
' <(printf "%s\n" "${persons[@]}") txt.ini
与:
$ typeset -p persons
declare -a persons=([0]="person_0" [1]="person_1" [2]="person_2")
两组awk
代码生成:
person_0
Group list =0,1,2
Age =30
person_1
Group list =0,4
Age =28
person_2
Group list =3,4
Age =30
注意: 这可以变得更加动态(public
and/or private
?不同的领域?)但这将需要更多编码
请您尝试以下操作:
awk -v RS='' ' # split the records on the blank lines
/public/ { # "public" record
split(, a, /[\[:]/); print a[2] # extract the "person_xx" substring
for (i = 2; i <= NF; i++) { # iterate over the lines of the record
split($i, a, /=/)
if (a[1] == "groups") print "Group list =" a[2]
else if (a[1] == "age") print "Age =" a[2]
}
print "" # insert a blank line
}
' txt.ini
输出:
person_0
Group list =0,1,2
Age =30
person_1
Group list =0,4
Age =28
person_2
Group list =3,4
Age =30
- 通过将
awk
变量RS
设置为空字符串,记录是 由空行分隔,字段由换行符分隔 字符。 - 假设所需数据包含在
public
块中, 我们可以一一解析public
记录的字段。
[编辑]
根据 OP 的评论,这里是更新版本:
#!/bin/bash
persons=("person_0") # list of desired person(s)
for person in "${persons[@]}"; do # loop over the bash array
awk -v RS='' -v person="$person" ' # assign awk variables
~ person ":public" { # "public" record of the person
split(, a, /[\[:]/); print a[2] # extract the "person_xx" substring
for (i = 2; i <= NF; i++) { # iterate over the lines of the record
split($i, a, /=/)
if (a[1] == "groups") print "Group list =" a[2]
else if (a[1] == "age") print "Age =" a[2]
}
}
' txt.ini
echo # insert a blank line
done
- 您可以将
persons
数组分配给任何您想要的人。 - 模式
~ person ":public"
测试记录的第一个字段</code>(例如 <code>[person_0:public]
)是否匹配 awk 变量person
(通过-v
选项)后跟字符串“:public”.
显然 awk 脚本多次重复读取 txt.ini
文件
persons
数组中#elements 的倍数。
如果 text.ini
文件很长 and/or 则 persons
数组有很多元素,
循环将是低效的。这是另一个变体:
#!/bin/bash
persons=("person_0" "person_1") # bash array just for an example
awk -v RS='' -v persons_list="${persons[*]}" '
# persons_list is a blank separated list of persons
BEGIN {
split(persons_list, a) # split persons_list back to an array
for (i in a) persons[a[i]] # create a new array indexed by person
}
/public/ { # "public" record
split(, a, /[\[:]/) # extract the "person_xx" substring
if (a[2] in persons) { # if the person exists in the list
print a[2]
for (i = 2; i <= NF; i++) { # iterate over the lines of the record
split($i, a, /=/)
if (a[1] == "groups") print "Group list =" a[2]
else if (a[1] == "age") print "Age =" a[2]
}
print "" # insert a blank line
}
}
' txt.ini
请注意,它假定人物字符串不包含空白字符。
如果是这样,请在将 persons_list
分配给未使用的时更改分隔符
逗号等字符。