如何在bash中从一行中获取名称?

如何在bash中从一行中获取名称?,bash,shell,Bash,Shell,我正在写一个接受某人id的脚本,该脚本应该打印此人的姓名!现在的问题是,我的名字是未知的 在我现在所在的目录中,我有一个文件,该文件中有行,每行的格式如下: id_编号来自6位数字的名称可以是任意长度,并且可以包括\u兄弟的结尾编号\u处的编号之间的正数 0-10个以上的随机数(6位数),但这是可选的 这意味着这里可能没有任何数字 名字的末尾可以包括一个数字,也可以在名字后面,必须有一个类似于兄弟数的数字,在这之后,可以选择在兄弟数之后包含id号,而我说的数字od包含6位数字 此外,行的开头可能

我正在写一个接受某人id的脚本,该脚本应该打印此人的姓名!现在的问题是,我的名字是未知的

在我现在所在的目录中,我有一个文件,该文件中有行,每行的格式如下:

id_编号来自6位数字的名称可以是任意长度,并且可以包括\u兄弟的结尾编号\u处的编号之间的正数 0-10个以上的随机数(6位数),但这是可选的 这意味着这里可能没有任何数字

名字的末尾可以包括一个数字,也可以在名字后面,必须有一个类似于兄弟数的数字,在这之后,可以选择在兄弟数之后包含id号,而我说的数字od包含6位数字 此外,行的开头可能有空格,每两个数字或名称之间至少有一个空格 例如:

234218丹·西蒙1 3 234122 234118 104134

我想知道的名字是丹·西蒙1

另一个例子:

236501克里斯·布朗歌手3

我想在这里得到的名字是克里斯·布朗·辛格

我的问题是如何得到这个名字!因为名字可以包含很多单词和数字

我首先去掉了行中多余的空格,然后通过grep获得包含正确id的行

#!/bin/bash

line = `grep ^$1 names_file`
correct_line=`echo $line`
输入文件:

下面是纯bash regex解决方案:

re='^[0-9]{6} +([a-zA-Z][a-zA-Z0-9 ]*) +[0-9]{1,2}( +[0-9]{6,})*$'

while IFS= read -r line; do [[ $line =~ $re ]] && echo "${BASH_REMATCH[1]}"; done < file

Dan simon 1
chris brown singer
John Right 2nd
详情:

^\d{6,}\s+:在开始处匹配6+个数字,后跟1+个空格 \K:重新设置比赛 [\w\s]+?:匹配1+个字或空格字符 ?=\s+\d{1,2}?:\s+\d{6,}*$:向前看以确保前面有年龄数字1或2
下面是使用awk解析文件的方法

awk '{
  # search backwards to find the first number between 0 and 10
  for (i = NF; i > 2; i--) {
    if (0 <= $i && $i <= 10) {
      brothers_col = i
      break
    }
  }
  if (i == 2) next          # did not find a name, skip this line
  name = ""
  for (i = 2; i < brothers_col; i++) {
    name = name $i OFS
  }
  print name
' file

您的第一行几乎肯定不会做您希望它做的事情,因为=。如果说您需要行的第二、第三和第四个字段,其中每个字段由一个或多个空格分隔,这是真的吗?因此,我应该首先删除空格,然后查找以给定id开头的行?显然,名称文件格式不正确。文件的字段中不应包含字段分隔符。您可以更改文件以使其更易于解析吗?这是一场噩梦。如果您控制文件结构,请不要使用空格作为字段分隔符。你的数据应该是这样的:234218,Dan Simon 1,3234122234118104134-那么第二个字段就很简单了。我没有完全理解这个问题:\n难道没有更简单的方法吗?也许可以使用cut?此外,第一行应该打印Dan simon 1您的正则表达式在结尾需要更多帮助:^\d{6,}\s++\K.+??=\s++\d{1,2}\s++\d{6,}*$-这应该可以找到1或2位数字,后面可以是6位以上的数字,直到结束。谢谢@glennjackman,我刚刚按照您的建议修改了这个正则表达式。@newprogrammerha您不能使用cut,因为您需要的字段数是可变的,是的,你是对的:我正在寻找别的东西
grep -oP '^\d{6,}\s+\K[\w\s]+?(?=\s+\d{1,2}(?:\s+\d{6,})*$)' file    
Dan simon 1
chris brown singer
John Right 2nd
awk '{
  # search backwards to find the first number between 0 and 10
  for (i = NF; i > 2; i--) {
    if (0 <= $i && $i <= 10) {
      brothers_col = i
      break
    }
  }
  if (i == 2) next          # did not find a name, skip this line
  name = ""
  for (i = 2; i < brothers_col; i++) {
    name = name $i OFS
  }
  print name
' file