搜索字段并向其显示下一个数据
Search field and display next data to it
有没有一种最简单的方法可以根据字段 @@id:
搜索具有特定字段的以下数据?
这是名为 sample
的示例数据文件
@@id: 123 @@name: John Doe @@age: 18 @@Gender: Male
@@id: 345 @@name: Sarah Benson @@age: 20 @@Gender: Female
例如,如果我想搜索 ID 为 123 和他的性别,我会这样做:
基本上这是我想要的原型:
# search.sh
#!/bin/bash
# usage: search.sh <id> <field>
# eg: search 123 age
search=""
field=""
grep "^@@id: ${search}" sample | # FILTER <FIELD>
所以当我像下面这样搜索 ID 123 时:
search.sh 123 gender
输出将是
Male
到目前为止,根据上面的代码,我只能根据 ID grep 一行,我不确定在指定后获取下一个值的最佳方法或最快的方法是什么字段(例如年龄)
由于您想提取找到的每一行的一部分,与您匹配的部分不同,sed
或 awk
将是比 grep
更好的工具。您可以将 grep
的输出通过管道传输到其他输出中,但这很浪费,因为 sed
和 awk
都可以直接进行行选择。我会做这样的事情:
#!/bin/bash
search=""
field=""
sed -n "/^@@id: ${search}"'\>/ { s/.*@@'"${field}"': *//i; s/ *@@.*//; p }' sample
解释:
sed
被指示读取文件 sample
,它将逐行执行。
-n
选项告诉 sed
抑制其在每个循环结束时自动输出其模式 space 的通常行为,这是一种过滤掉那些行的简单方法不符合搜索条件。
sed
表达式以 地址 开头,在本例中,根据脚本的第一个参数,它是一个通过 id 匹配行的模式。它很像您的 grep
模式,但我附加了 \>
,它匹配单词边界。这样,搜索 id 123 将不会同时匹配 id 1234。
-
sed
表达式的其余部分编辑掉行中除请求字段值之外的所有内容,字段名称不区分大小写地匹配,并打印结果。编辑是通过两个s///
命令完成的,p
命令当然是为了“打印”。这些都包含在大括号 ({}
) 中并用分号 (;
) 分隔,以形成与给定地址关联的单个化合物。
假设:
- 'label' 字段的格式为
@@<string>:
- 需要处理不区分大小写的搜索
- 'label' 字段可以位于行中的任何位置(即,'label' 字段没有设置顺序)
- 第一个输入搜索参数始终是与
@@id:
标签关联的值
- 第二个输入搜索参数将作为整个词匹配(即,没有部分标签匹配;
nam
不会与 @@name:
匹配)
- 如果有多个 'label' 字段与第二个输入搜索参数匹配,我们打印与行中找到的第一个匹配项关联的值)
一个awk
想法:
awk -v search="${search}" -v field="${field}" '
BEGIN { field = tolower(field) }
{ n=split([=10=],arr,"@@|:") # split current line on dual delimiters "@@" and ":", place fields into array arr[]
found_search = 0
found_field = 0
for (i=2;i<=n;i=i+2) { # loop through list of label fields
label=tolower(arr[i])
value = arr[i+1]
sub(/^[[:space:]]+/,"",value) # strip leading white space
sub(/[[:space:]]+$/,"",value) # strip trailing white space
if ( label == "id" && value == search )
found_search = 1
if ( label == field && ! found_field )
found_field = value
}
if ( found_search && found_field )
print found_field
}
' sample
示例输入:
$ cat sample
@@id: 123 @@name: John Doe @@age: 18 @@Gender: Male
@@id: 345 @@name: Sarah Benson @@age: 20 @@Gender: Female
@@name: Archibald P. Granite, III, Ph.D, M.D. @@age: 20 @@Gender: not specified @@id: 567
测试运行:
search=123 field=gender => Male
search=123 field=ID => 123
search=123 field=Age => 18
search=345 field=name => Sarah Benson
search=567 field=name => Archibald P. Granite, III, Ph.D, M.D.
search=567 field=GENDER => not specified
search=999 field=age => <no output>
第一个解决方案: 使用您显示的示例,请尝试遵循 bash 脚本。这考虑到你想要匹配精确的字符串匹配。
cat script.bash
#!/bin/bash
search=""
field=""
awk -v search="$search" -v field="$field" '
match([=10=],"@@id:[[:space:]]*"search){
value=""
match([=10=],"@@"field":[[:space:]]*[^@]+")
value=substr([=10=],RSTART,RLENGTH)
sub(/.*: +/,"",value)
print value
}
' Input_file
第二个解决方案:如果你想搜索字符串(值)而不考虑它们的大小写(lower/upper大小写)在每一行中然后尝试以下代码。
cat script.bash
#!/bin/bash
search=""
field=""
awk -v search="$search" -v field="$field" '
match(tolower([=11=]),"@@id:[[:space:]]*"tolower(search)){
value=""
match(tolower([=11=]),"@@"tolower(field)":[[:space:]]*[^@]+")
value=substr([=11=],RSTART,RLENGTH)
sub(/.*: +/,"",value)
print value
}
' Input_file
解释: 代码的简单解释是,创建 BASH 脚本,它在执行时需要 2 个参数运行。然后将这些参数作为值传递给 awk
程序。然后使用 match
函数匹配每行中的 id 并打印传递的字段的值(例如:姓名或性别等)。
对于给定的数据格式,您可以将字段分隔符设置为可选空格,后跟 @@
以防止打印字段出现尾随空格。
然后每行创建一个键值映射(使键和字段搜索小写)并搜索键,这将与字符串中的顺序无关。
如果密钥存在,则打印值。
#!/bin/bash
search=""
field=""
awk -v search="${search}" -v field="${field}" '
BEGIN {FS="[[:blank:]]*@@"} # Set field separator to optional spaces and @@
{
for (i = 1; i <= NF; i++) { # Loop all the fields
split($i, a, /[[:blank:]]*:[[:blank:]]*/) # Split the field on : with optional surrounded spaces
kv[tolower(a[1])]=a[2] # Create a key value array using the splitted values
}
val = kv[tolower(field)] # Get the value from kv based on the lowercase key
if (kv["id"] == search && val) print val # If there is a matching key and a value, print the value
}' file
然后运行
./search.sh 123 gender
输出
Male
有没有一种最简单的方法可以根据字段 @@id:
搜索具有特定字段的以下数据?
这是名为 sample
@@id: 123 @@name: John Doe @@age: 18 @@Gender: Male
@@id: 345 @@name: Sarah Benson @@age: 20 @@Gender: Female
例如,如果我想搜索 ID 为 123 和他的性别,我会这样做:
基本上这是我想要的原型:
# search.sh
#!/bin/bash
# usage: search.sh <id> <field>
# eg: search 123 age
search=""
field=""
grep "^@@id: ${search}" sample | # FILTER <FIELD>
所以当我像下面这样搜索 ID 123 时:
search.sh 123 gender
输出将是
Male
到目前为止,根据上面的代码,我只能根据 ID grep 一行,我不确定在指定后获取下一个值的最佳方法或最快的方法是什么字段(例如年龄)
由于您想提取找到的每一行的一部分,与您匹配的部分不同,sed
或 awk
将是比 grep
更好的工具。您可以将 grep
的输出通过管道传输到其他输出中,但这很浪费,因为 sed
和 awk
都可以直接进行行选择。我会做这样的事情:
#!/bin/bash
search=""
field=""
sed -n "/^@@id: ${search}"'\>/ { s/.*@@'"${field}"': *//i; s/ *@@.*//; p }' sample
解释:
sed
被指示读取文件sample
,它将逐行执行。-n
选项告诉sed
抑制其在每个循环结束时自动输出其模式 space 的通常行为,这是一种过滤掉那些行的简单方法不符合搜索条件。sed
表达式以 地址 开头,在本例中,根据脚本的第一个参数,它是一个通过 id 匹配行的模式。它很像您的grep
模式,但我附加了\>
,它匹配单词边界。这样,搜索 id 123 将不会同时匹配 id 1234。-
sed
表达式的其余部分编辑掉行中除请求字段值之外的所有内容,字段名称不区分大小写地匹配,并打印结果。编辑是通过两个s///
命令完成的,p
命令当然是为了“打印”。这些都包含在大括号 ({}
) 中并用分号 (;
) 分隔,以形成与给定地址关联的单个化合物。
假设:
- 'label' 字段的格式为
@@<string>:
- 需要处理不区分大小写的搜索
- 'label' 字段可以位于行中的任何位置(即,'label' 字段没有设置顺序)
- 第一个输入搜索参数始终是与
@@id:
标签关联的值 - 第二个输入搜索参数将作为整个词匹配(即,没有部分标签匹配;
nam
不会与@@name:
匹配) - 如果有多个 'label' 字段与第二个输入搜索参数匹配,我们打印与行中找到的第一个匹配项关联的值)
一个awk
想法:
awk -v search="${search}" -v field="${field}" '
BEGIN { field = tolower(field) }
{ n=split([=10=],arr,"@@|:") # split current line on dual delimiters "@@" and ":", place fields into array arr[]
found_search = 0
found_field = 0
for (i=2;i<=n;i=i+2) { # loop through list of label fields
label=tolower(arr[i])
value = arr[i+1]
sub(/^[[:space:]]+/,"",value) # strip leading white space
sub(/[[:space:]]+$/,"",value) # strip trailing white space
if ( label == "id" && value == search )
found_search = 1
if ( label == field && ! found_field )
found_field = value
}
if ( found_search && found_field )
print found_field
}
' sample
示例输入:
$ cat sample
@@id: 123 @@name: John Doe @@age: 18 @@Gender: Male
@@id: 345 @@name: Sarah Benson @@age: 20 @@Gender: Female
@@name: Archibald P. Granite, III, Ph.D, M.D. @@age: 20 @@Gender: not specified @@id: 567
测试运行:
search=123 field=gender => Male
search=123 field=ID => 123
search=123 field=Age => 18
search=345 field=name => Sarah Benson
search=567 field=name => Archibald P. Granite, III, Ph.D, M.D.
search=567 field=GENDER => not specified
search=999 field=age => <no output>
第一个解决方案: 使用您显示的示例,请尝试遵循 bash 脚本。这考虑到你想要匹配精确的字符串匹配。
cat script.bash
#!/bin/bash
search=""
field=""
awk -v search="$search" -v field="$field" '
match([=10=],"@@id:[[:space:]]*"search){
value=""
match([=10=],"@@"field":[[:space:]]*[^@]+")
value=substr([=10=],RSTART,RLENGTH)
sub(/.*: +/,"",value)
print value
}
' Input_file
第二个解决方案:如果你想搜索字符串(值)而不考虑它们的大小写(lower/upper大小写)在每一行中然后尝试以下代码。
cat script.bash
#!/bin/bash
search=""
field=""
awk -v search="$search" -v field="$field" '
match(tolower([=11=]),"@@id:[[:space:]]*"tolower(search)){
value=""
match(tolower([=11=]),"@@"tolower(field)":[[:space:]]*[^@]+")
value=substr([=11=],RSTART,RLENGTH)
sub(/.*: +/,"",value)
print value
}
' Input_file
解释: 代码的简单解释是,创建 BASH 脚本,它在执行时需要 2 个参数运行。然后将这些参数作为值传递给 awk
程序。然后使用 match
函数匹配每行中的 id 并打印传递的字段的值(例如:姓名或性别等)。
对于给定的数据格式,您可以将字段分隔符设置为可选空格,后跟 @@
以防止打印字段出现尾随空格。
然后每行创建一个键值映射(使键和字段搜索小写)并搜索键,这将与字符串中的顺序无关。
如果密钥存在,则打印值。
#!/bin/bash
search=""
field=""
awk -v search="${search}" -v field="${field}" '
BEGIN {FS="[[:blank:]]*@@"} # Set field separator to optional spaces and @@
{
for (i = 1; i <= NF; i++) { # Loop all the fields
split($i, a, /[[:blank:]]*:[[:blank:]]*/) # Split the field on : with optional surrounded spaces
kv[tolower(a[1])]=a[2] # Create a key value array using the splitted values
}
val = kv[tolower(field)] # Get the value from kv based on the lowercase key
if (kv["id"] == search && val) print val # If there is a matching key and a value, print the value
}' file
然后运行
./search.sh 123 gender
输出
Male