提取同一行上两个搜索模式之间的值

提取同一行上两个搜索模式之间的值

我在文件 Output.dat 中有以下内容。我需要提取dn: uid=和之间的值,ou=

 dn: uid=user1,ou=Active,ou=Member,dc=domain,dc=org
 dn: [email protected],ou=Active,ou=Member,dc=domain,dc=org
 dn: uid=usertest,ou=Active,ou=Member,dc=domain,dc=org
 dn: uid=abc1,ou=Active,ou=Member,dc=domain,dc=org
  • 我尝试使用
    sed -e '/dn: uid=/,/,ou=/p' output.dat but
    
    它返回完整的行而不是值。
  • 当尝试使用时
    sed -e '/dn: uid=/,/,ou=/\1/p' output.dat
    
    然后得到以下错误:
    sed: -e expression #1, char 18: unknown command: `\'
    

答案1

如果您有一个支持 PCRE ( ) 的 GNU grep 版本-P,那么假设您的意思是第一的的发生,ou

grep -oP '(?<=dn: uid=).+?(?=,ou=)' file

如果你想匹配第二 ,ou您可以删除非贪婪?修饰符

grep -oP '(?<=dn: uid=).+(?=,ou=)' file

括号中的表达式是零长度断言(又名环顾四周) 意味着它们构成匹配的一部分,但不会作为结果的一部分返回。你可以在 perl 中本地做同样的事情,例如

perl -ne 'print "$1\n" if /(?<=dn: uid=)(.+?)(?=,ou=)/' file 

做某事是可能的相似的在 sed 中,使用常规(非零长度)分组,例如(对于 GNU sed - 其他变体可能需要额外转义)

sed -rn 's/(.*dn: uid=)([^,]+)(,ou=.*)/\2/p' file

或稍微简化

sed -rn 's/.*dn: uid=([^,]+),ou=.*/\1/p' file

请注意,[^,]这里有点 hack,因为 sed 没有真正的非贪婪匹配选项。


事后的想法:虽然这并不完全符合您的要求,但看起来您真正想要做的是name=value从文件中读取逗号分隔的对,然后进一步将第一个字段的值与其名称分开。您可以通过多种方式实现这一目标 - 包括

awk -F, '{sub(".*=","",$1); print $1}' file

或纯 bash 解决方案,例如

while IFS=, read -r a b c d; do printf '%s\n' "${a#*=}"; done < file 

答案2

这对于 awk 来说是一个很好的工作。您可以拆分字符串,而不是尝试使用正则表达式。这是一个解决方案:

$ awk -F= '{ split($2,arr,","); print arr[1]  }' test.txt
user1
[email protected]
usertest
abc1

答案3

sed

sed 's/[^=]*=\([^,]\+\),.*/\1/' file

这假设uid=将在该行上第一次出现=,并且假设您想在,ou=该行的第一个实例处停止。

解释

这将查找任意数量的非=字符 ( [^=]*) 后跟=then 匹配,并保存尽可能多的非逗号 ( \([^,]\+\)) 后跟逗号以及该行的其余部分 ( ,.*)。这意味着它将用它在该行=第一个逗号之后找到的任何非逗号字符替换第一个逗号之前和之后的所有内容。=

答案4

还有一些选择,按长度顺序排列:

  1. grep带有 PCRE 的GNU

    grep -oP 'uid=\K[^,]+' file 
    

    丢弃\K与该点匹配的所有内容,与-o开关结合将导致仅打印后的grep最长非字符。,uid=

  2. awk

    awk -F'[=,]' '{print $2}' file 
    

    -F'[=,]将字段分隔符设置为或者=第二,个字段是用户名。

  3. sed

    sed -r 's/.{8}([^,]*).*/\1/' file 
    

    这将匹配前 7 个字符 ( .{7}) =,捕获最长的非,as部分\1并将整行替换为\1

  4. perl

    perl -pe 's/.+?=([^,]+).*/$1/' file 
    

    意思-pe是“在应用 -e 给出的脚本后打印每一行”。是s///替换运算符,正则表达式查找第一个(.+??使其匹配最短的可能字符串) ,然后捕获此后=最长的非字符段。,替换s///与捕获的内容(括号内的内容)匹配的内容。

  5. cut

    cut -d'=' -f 2 file | cut -d ',' -f 1 
    

    -d分隔符设置为,=因此第二个 ( -f 2) 字段为username,ou。第二个cut用作,分隔符并单独打印用户名。

相关内容