搜索字段并向其显示下一个数据

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 一行,我不确定在指定后获取下一个值的最佳方法或最快的方法是什么字段(例如年龄)

由于您想提取找到的每一行的一部分,与您匹配的部分不同,sedawk 将是比 grep 更好的工具。您可以将 grep 的输出通过管道传输到其他输出中,但这很浪费,因为 sedawk 都可以直接进行行选择。我会做这样的事情:

#!/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