【问题标题】:Pulling values from List - Unix Shell从列表中提取值 - Unix Shell
【发布时间】:2016-01-06 10:32:33
【问题描述】:

我正在尝试从列表中提取特定值。我的输入如下所示:

$ cat data.txt

Name: Mike
Age: 20
Date: June 1st
Color: Red

Name: Jon
Age: 22
Date: May 3rd
Color: Blue

Name: Jamie
Age: 18
Date: December 21st
Color: Green

Name: Chris
Age: 24
Date: July 5th
Color: Blue

然后我执行以下命令来提取一些数据:

grep Name data.txt|cut -c6-20 ;  grep Color data.txt|cut -c7-20

返回:

Mike
Jon
Jamie
Chris
Red
Blue
Green
Blue

我希望它返回更像这样的东西:

Mike:Red
Jon:Blue
Jamie:Green
Chris:Blue

最后我希望能够指定 Color=blue 然后输出:

Jon
Chris

任何帮助完成这项工作将不胜感激。我对 bash 脚本非常陌生,并且一直在尝试通过这个网站和其他网站自学。

提前致谢!

【问题讨论】:

  • 不要使用grep。使用awk

标签: bash shell unix command-line grep


【解决方案1】:

anubhava 一如既往地提供了正确而简洁的解决方案。

但与 unix 中的所有内容一样,有不止一种方法可以做到这一点。

为了后代,我将提供一个仅限 bash 的答案。

请注意,bash 和 awk 都不提供多维数组或对象,因此您的数据结构有点受限。在您的情况下,我将假设“名称”字段在记录中是唯一的,这意味着它可以像“主键”一样使用。

我们可以读取您的输入文件并使用键填充多个 bash 数组。好吧,键。

#!/usr/bin/env bash

# Note that "declare -A", which sets an associative array, requires bash 4.
declare -A Age Date Color

while IFS=': ' read field value; do
  if [ -z "$field" ]; then
    continue
  elif [ "$field" = Name ]; then
    key="$value"
    continue
  fi
  eval $field["\$key"]="\$value"
done < data.txt

这样做的结果是您将拥有一组数组,其键是数据文件中的名称,其值是这些名称后面的相应字段。

对于第一个任务:

for Name in "${!Color[@]}"; do
  printf "%s:%s\n" "$Name" "${Color[$Name]}"
done

第二个任务:

for Name in "${!Color[@]}"; do
  if [ "${Color[$Name]}" = "Blue" ]; then
    printf "%s\n" "$Name"
  fi
done

请注意,"${!Color[@]}" 中的感叹号导致 bash 返回索引列表而不是值列表。显然,可以使用索引来访问这些值。

显然,不如 awk 简洁,但如果您需要随机访问数组中的数据,直接在 shell 中处理这类事情会很有用。

【讨论】:

    【解决方案2】:

    使用 awk 你可以做到这一点。

    第一个任务:

    awk -F' *: *|\n' -v RS= '{print $2 ":" $8}' data.txt
    Mike:Red
    Jon:Blue
    Jamie:Green
    Chris:Blue
    

    第二个任务:

    awk -F' *: *|\n' -v RS= -v Color=Blue '$8 == Color{print $2}' data.txt
    Jon
    Chris
    

    【讨论】:

    • 非常感谢。这正是我所需要的。我喜欢了解这些命令在做什么,而不是盲目地复制代码,所以我将在awk 上阅读更多内容。这似乎是一个强大的命令。再次感谢!
    • -v RS=' sets record separator as null thus giving us each block in single record. -F' *: *|\n'` 将输入字段分隔符设置为用可选空格或新行包围的冒号。我强烈建议您阅读 awn 教程。
    • @VanCityGuy,awk 不仅仅是一个强大的命令,它是一门完整的语言,并且非常适合某些任务。如果您处理文本,您可能想学习 awk。 :)
    猜你喜欢
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-17
    • 2020-09-06
    • 2010-10-11
    相关资源
    最近更新 更多