Sed 匹配一行并返回包含模式的匹配之前的前一行

Sed 匹配一行并返回包含模式的匹配之前的前一行,sed,Sed,我正在编写一个bash脚本,该脚本位于一个包含多个条目的文件中,其中每个条目都具有以下结构: Id: 33239 Folder: /Contacts/Holder/Center Date: 04/17/20 13:17 Revision: 34011 Attrs: firstName: Name lastName: First Second mobilePhone: +345555555 fileAs: 2 jobTitle: Médico company: some c

我正在编写一个bash脚本,该脚本位于一个包含多个条目的文件中,其中每个条目都具有以下结构:

Id: 33239
Folder: /Contacts/Holder/Center
Date: 04/17/20 13:17
Revision: 34011
Attrs:
  firstName: Name
  lastName: First Second
  mobilePhone: +345555555
  fileAs: 2
  jobTitle: Médico
  company: some company
  email: test_1@somedomain.com
我需要找到与特定“电子邮件”关联的项目的“Id”。为了做到这一点,我试着用“sed”加上hold。但是我没有达到我的目标。这就是我目前所拥有的,但我没有得到我需要的结果

id=$(grep$usuario-B20/tmp/contactos\
|grep“文件夹:/Contacts/Holder”-B2-A20\
|sed-n“/^Id:/h;/^email:$usuario/{g;p;}”\
|awk'{print$2}')
通过这一点,我试图:

id=
-将值分配给我稍后将在脚本中使用的变量

$(grep$usuario-B20/tmp/contactos
-获取文件中显示电子邮件的所有行,并在其前面获取20行。这是因为电子邮件显示时与多个
Id
关联,Id本身下面的行数不确定

grep'文件夹:/Contacts/Holder'-B2-A20
-我再次过滤,现在尝试只获取特定“文件夹路径”中该电子邮件ID的结果

sed-n'/^Id:/h;/^email:$usuario/{g;p;}
-这是不起作用的部分,我不知道如何修复它。在这里,我尝试返回包含与电子邮件关联的
Id:
的行。在本例中类似于:
Id:33239

awk'{print$2}')
-我只想打印那一行的数字(
33239

请任何人帮助理解我如何使用sed`或者如果有其他选择,我也非常欢迎:)


多谢各位

此sed命令应将其解压缩:

sed-n'
/^Id://{#如果该行以“Id:”开头:
删除“Id:”
h#将剩余物品存放在货舱空间
}
/^电子邮件:“$email”/{#如果行以“email:”开头,加上电子邮件
x#交换模式和保持空间
p#打印图案空间
q#停止处理
}
“填充
其中
$email
是包含
测试转义版本的shell变量_1@somedomain.com

原始测试_1@somedomain.com' 电子邮件=$(sed's |[]/.^$\[]\\\\&| g'
  • 默认字段分隔符在空格/制表符/换行符上拆分,并从字段内容中删除前导/尾随空格
  • $1==“email:
    检查第一个字段内容是否完全是
    email:
    (这是字符串比较,不是regexp)
  • $1==“电子邮件:&&&$2==”测试_1@somedomain.com“
    如果两个条件都满足,则打印
    id
    变量
  • $1==“Id:{Id=$2}
    每当第一个字段是
    Id:

在这里,我使用了硬编码字符串值来检查电子邮件,请参见了解如何传递shell变量这里有两个愚蠢的纯
bash
方法(无外部UTIL),这是一种需要恒定数量的字段名和属性的通用方法,以及(仅第一种方法)一个相对较短的输入文件:

  • 同样的事情也可以通过大量使用
    read
    来完成:

    while read a Id && read a Folder && read && read && read &&
          read && read && read && read && read && read && 
          read a email; do
          [[ $email == test_1@somedomain.com &&
             $Folder == /Contacts/Holder/Center ]] &&
          echo $Id
    done < infile
    
    读取Id时读取文件夹时读取&&
    读&&read&&read&&read&&read&&read&&read&&
    读电子邮件;做某事
    [$email==测试_1@somedomain.com &&
    $Folder==/Contacts/Holder/Center]]&&
    echo$Id
    完成<填充
    

  • 在大图中,您正在尝试将文件夹和电子邮件上的条件链接在一起以生成Id。因此
    awk
    是解决整个问题的更好选择。如果您的Bash脚本可以准备下面的脚本,则您可以这样调用它:

    id=$(awk-f/tmp/script.awk-v usario=test\u 1/tmp/contactos)

    下面是Bash脚本应该写入的内容
    /tmp/script.awk

    /Id:/   { id=$2; folder="" }
    /Folder:..Contacts.Holder/  { folder=$2 }
    /email:/    { if (match($2, "^" usario "@") && folder != "") print id }
    
    您应该注意“匹配前缀”问题。例如查找“juan”而不匹配“juanita”。这就是脚本使用
    match()
    函数的原因,该函数的计算结果类似于
    match($2,“^juan”)
    。该正则表达式将完全匹配”juan@domain.com“不匹配”juanita@domain.com”“或者"somejuan@domain.com“


    注意:
    awk
    语法连接由空格分隔的字符串和变量。正如他们所说,这“需要一些习惯”。如果有帮助,您可以在
    “^”usario“@”周围添加括号…

    类似于
    awk'$1==”email:&&$2==”测试_1@somedomain.com“{print id}$1==”id:{id=$2}”“input_file
    ?这很好!不……我不觉得我浪费了2个小时在你2分钟内解决的问题上有什么不好(你听不到,但其中有很多讽刺:P).你能告诉我它是如何运作的吗?我想这门功夫对其他东西也会很有用。非常感谢!好吧,我可以很容易地解决它,因为我以前遇到过这样的问题,现在已经使用awk好几年了。.请参阅学习资源请澄清Attr:道具的数量是否恒定,(示例中有7个),或者可能有所不同(即大于或小于7个)。纯shell方法当然效率低下,但在工作琐碎且资源非常有限的情况下可能有用,例如嵌入式系统。太棒了。非常感谢!!!这也很有魅力!
    printf '%0.0s%s%0.0s %s%0.0s%0.0s%0.0s%0.0s%0.0s%0.0s%0.0s'\
        '%0.0s%0.0s%0.0s%0.0s%0.0s%0.0s%0.0s%0.0s%0.0s%0.0s'\
        '%0.0s%0.0s%0.0s%0.0s %s\n' $(<infile) | 
        while read Id Folder email; do 
            [[ $email == test_1@somedomain.com && 
               $Folder == /Contacts/Holder/Center ]] && 
            echo $Id
        done
    
    33239 /Contacts/Holder/Center test_1@somedomain.com
    
    while read a Id && read a Folder && read && read && read &&
          read && read && read && read && read && read && 
          read a email; do
          [[ $email == test_1@somedomain.com &&
             $Folder == /Contacts/Holder/Center ]] &&
          echo $Id
    done < infile
    
    /Id:/   { id=$2; folder="" }
    /Folder:..Contacts.Holder/  { folder=$2 }
    /email:/    { if (match($2, "^" usario "@") && folder != "") print id }