【问题标题】:Read word from a file and return next word从文件中读取单词并返回下一个单词
【发布时间】:2012-09-23 12:50:09
【问题描述】:

使用 shell 脚本我想从文本文件中读取一个单词并返回下一列单词。

例如,我的输入文件会是这样的

AGE1 PERSON1
AGE2 PERSON2
AGE3 PERSON3
AGE4 PERSON4

我在 Sh 文件中有一个具有 PE​​RSON 名字的变量。 我想读取输入文本文件并获取人的年龄值。

请帮忙,我是 Shell 脚本的初学者

【问题讨论】:

  • 阅读grepcut。祝你好运。
  • 您的问题是“下一列”,但在您的示例中,它是上一列——是哪一列?该文件是否可以包含多于两列,或者它总是与您的示例完全一样?

标签: perl unix awk grep sh


【解决方案1】:

一个稍微简单的解决方案是:

age=$( awk '$2==name { print $1 }' name="$name" input-file )

【讨论】:

  • 为什么不使用 awk 的 -v 选项,这样您就不必取消引用?
  • @Barmar 很好的建议!
【解决方案2】:

基于 shellter 的评论:

age=$(grep "$person_name" people_file.txt | cut -f1 -d' ')

我会尽力解释一切。首先,我假设一些东西(但你可以在你的脚本上改变它们):

  1. 您输入的数据文件名为people_file.txt
  2. 您要查找的人名在变量$person_name 中。
  3. 您要存储结果的变量是$age

首先,因为我们需要使用命令来生成$age变量的值,所以我们必须使用$()来运行一个命令(或一系列命令),并将其自身替换为文本它从执行命令(或命令)中捕获。

我们首先需要找到包含人名的行。为此,我们使用 grep:grep regex file。 Grep 将逐行搜索file,直到找到与正则表达式regex 匹配的行。在我们的例子中,我们可以简单地直接搜索人名(假设它不包含特殊字符,如句点或星号)。请注意,我们必须将变量放在双引号之间,否则在命令行中可能会拆分包含空格的人名,以便将其名字用作正则表达式,将姓氏用作文件。如果您想以不区分大小写的方式进行搜索(例如:John 将找到带有 JOHN 或 john 的行),您可以使用 -i 标志:grep -i regex file。选定的行将由 grep 打印到其输出中,但我们将使用管道运算符 | 将这些行泵入下一个命令的输入。

最后,我们有一行(或多行)的结果。现在我们必须提取年龄。 cut 命令将从输入中读取的每一行拆分为字段,并且只打印您要求它的字段。在这种情况下,我们要求使用 -f1 选项的第一个字段。此外,我们通过-d1 命令指定将空格字符用作分隔符(即分隔字段的字符)。

如果您有多行同一个人的姓名,我们需要将 grep 的输出通过管道传输到 head 命令中,这样我们就可以只拥有我们想要的行数。我们可以使用 -n N 选项告诉 head 我们想要多少行。所以如果你只想要第一场比赛:

age=$(grep "$person_name" people_file.txt | head -n 1 | cut -f1 -d' ')

希望这会有所帮助 =)

【讨论】:

  • 非常感谢 Janito。感谢您深入教导我的努力。 :)
  • 您的代码不起作用。当您搜索 Jon 时,它会返回 Jonathan 的年龄。
  • 您必须小心您的搜索选项。请记住,grep 搜索正则表达式。如果您确定$person_name 包含全名,则可以使用grep "$person_name\$" file 确保该行以名称结尾,或者甚至使用grep "$person_name\\s" file 确保名称后有空格。跨度>
  • 您提到的尚未应用的修复仍将允许Anne 匹配Marie-Anne。还有一个可能的问题是L. Brine 将匹配Lo Brine。 (我的解决方案没有这些问题。)
  • 再一次,我们可以使事情进一步复杂化。它可以变成:$(grep "\s$(printf "%s\\n" "$person_name" | sed -e 's/[^./\\$]/\\&/g')$" file | head -n1 | cut -f1 -d' '),它将转义正则表达式的所有特殊字符,保证查询以空格字符开头并在行尾结束。我们甚至可以在 cut 命令之后附加|| echo "Person not found" >&2。但是我认为这些更改对于这篇文章来说太复杂了,这就是我现在不考虑应用这些“修复”的原因。除非,当然,Maulzey 想要我。
【解决方案3】:
age=`
   perl -nle'
      BEGIN { $n = shift(@ARGV); }
      print $1 if /^(\S+)\s+\Q$n\E$/;
   ' "$name" file
`

sh 模式下使用bash 测试。

【讨论】:

  • 嗨,非常感谢您的帮助。在执行时我得到“无法识别的开关:-E”你能帮忙吗?
  • 针对早于 5.10 的 Perl 版本进行了调整。请记住,5.14 是受支持的最古老的 Perl 版本,因此您的版本实际上已经很旧了。
猜你喜欢
  • 1970-01-01
  • 2016-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-24
  • 2017-04-15
  • 1970-01-01
  • 2011-06-02
相关资源
最近更新 更多