【问题标题】:How to extract specific lines from a file using bash如何使用 bash 从文件中提取特定行
【发布时间】:2017-06-13 22:04:54
【问题描述】:

我正在编写一个脚本,该脚本应该从命令结果中提取特定类型的用户及其对应的 uidNumber 并将其输出到文件中。示例命令结果为:

dn: uid=test_user_2,ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot
cn: test_user_2
uid: test_user_2
uidNumber: 10000
gidNumber: 400
homeDirectory: /home/test_user_2
userPassword:: e2NyeXB0fSo=

dn: uid=test_user_3,ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot
cn: test_user_3
uid: test_user_3
uidNumber: 500
gidNumber: 400
homeDirectory: /home/test_user_2
userPassword:: e2NyeXB0fSo=

dn: cn=test_group_3,ou=Group,fsFragmentId=Security,fsClusterId=ClusterRoot
cn: test_group_3
gidNumber: 10000
homeDirectory: /home/test_user_3
userPassword:: e2NyeXB0fSo=

我想用"ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot"uidNumber 用10000 到60000 打印所有用户

我已经提取了带有"ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot" 的行但是,我不知道如何提取其对应的uidNumber

我使用了下面的命令:

$LDAP_command | grep "dn: uid=.*,ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot" > ldapsearch_extracted.txt

预期的输出应该是这样的:

dn: uid=test_user_2,ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot
uidNumber: 10000

【问题讨论】:

    标签: linux bash shell awk grep


    【解决方案1】:

    sed -n '/^\(dn\|uidNumber\):/H;/^$/ba;$ba;bb;:a;x;/uidNumber: [1-5][0-9]\{4\}\b/p;:b' <file.txt 
    
    dn: uid=test_user_2,ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot
    uidNumber: 10000
    

    sed -n '/^\(dn:.*ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot\|uidNumber:\)/H;/^$/ba;$ba;bb;:a;x;/uidNumber: [1-5][0-9]\{4\}/p;:b' <file.txt
    

    解释:

    可以写成:

    sed -n '
        /^\(dn\|uidNumber\):/H;
        /^$/ba;
        $ba;
        bb;
       :a;
        x;
        /uidNumber: [1-5][0-9]\{4\}\b/p;
       :b
      ' <file.txt 
    
    • 搜索^dn:^uidNumber,然后添加到保留空间
    • 在空行上^$ 分支到标签:a
    • 在最后一行分支到标签:a
    • 标记:b的分支
    • 标签:a
      • 保持空间交换当前模式空间(空行)
      • 如果uidNumber: [1-5][0-9]\{4\}(包括从1000059999),则打印
    • 标签:b(循环到下一行)

    或者

    sed -n '
         /^dn:.*ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot/H;
         /^uidNumber:/H;
         /^$/ba;
         $ba;
         bb;
        :a;
         x;
         /uidNumber: [1-5][0-9]\{4\}\b/p;
        :b
       ' <file.txt
    

    有明确的条件:

    sed -n '
        /^\(dn\|uidNumber\|gidNumber\):/H;
        /^$/ba;
        $ba;
        bb;
      :a;
        x;
        /uidNumber: [1-5][0-9]\{4\}\b/{
            /ou=People/{
                /fsFragmentId=Security/{
                    /fsClusterId=ClusterRoot/{
                        p;
                    }
                }
            }
        };
      :b
        ' <file.txt
    

    这会

    • 将 dn、uidNumber 和 gidNumber 存储在保持空间中,
    • 在最后一行或空行上,如果 uidNumber: [1-5][0-9]{4}(包括从 10000 到 59999),则
      • 如果 ou=People,则
        • 如果 fsFragmentId=Security,那么
          • 如果 fsClusterId=ClusterRoot,则打印。

    这样做的主要优点是确保这项工作与dn 行上的另一个变量顺序一起工作。

    【讨论】:

    • 太棒了!这正是我想要输出的。非常感谢!
    • 我可以将这部分:/^\(dn\|uidNumber\):/H; 编辑为:/^\(dn: cn\|gidNumber\):/H;,以便我也可以打印组吗?我已经编辑了关于这个问题的示例
    • @EdMorton uidNumber 介于 10000 和 60000 之间!
    • @EdMorton 只需在某处添加 /^gidNumber/H;,在第一 2 行(在分支 :b 之前)。
    • @EdMorton 好的,我错过了 $ 来标记行尾,或者 \b 来标记边界,谢谢!
    【解决方案2】:

    你可以试试下面的命令,

    awk '
      /ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot/{print} 
      /uidNumber/{if ($2>=10000 && $2<=60000)print}
    ' file
    

    【讨论】:

    • 您好,这行得通!但是,无论uidNumber如何,它都会打印所有用户,我希望使用uidNumber 10000 - 60000打印用户
    • @NicaRivera 没问题,我修改答案来限制uidNumber。
    【解决方案3】:

    只要您的输入中有名称=值对,到目前为止,最清晰、最简单和最可扩展的方法是首先创建一个包含该映射的数组(下面的f[]),然后您可以通过以下方式访问值他们的名字:

    $ cat tst.awk
    BEGIN { RS=""; FS=OFS="\n"; ORS="\n\n" }
    {
        delete f
        for (i=1; i<=NF; i++) {
            name = value = $i
            sub(/:.*/,"",name)
            sub(/^[^:]+:+[[:space:]]*/,"",value)
            f[name] = value
        }
    }
    (f["dn"] ~ /ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot/) &&
            (f["uidNumber"]+0 >= 10000) && (f["uidNumber"]+0 <= 60000) {
        print p("dn"), p("uidNumber")
    }
    function p(n) { return n ": " f[n] }
    
    $ awk -f tst.awk file
    dn: uid=test_user_2,ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot
    uidNumber: 10000
    

    显然,只要遵循上述结构,您想要执行其他任何操作来实现其他条件和/或以您喜欢的任何顺序打印其他字段都是完全微不足道的。

    想要打印gidNumber?只需将打印语句更改为:

        print p("dn"), p("uidNumber")
    

    到:

        print p("dn"), p("uidNumber"), p("gidNumber")
    

    想要打印第二条记录?换个方式

    (f["dn"] ~ /ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot/) &&
            (f["uidNumber"]+0 >= 10000) && (f["uidNumber"]+0 <= 60000) {
    

    到:

    NR==2 {
    

    想要打印cn == uid 的记录?将以上内容更改为:

    f["cn"] == f["uid"] {
    

    想要打印未填充uidNumber 的记录?将以上内容更改为:

    f["uidNumber"] == "" {
    

    这以及您可能想要对字段的任何组合执行的任何其他操作都是完全显而易见、微不足道且一致的。

    上面是在下面的文件上运行的,你不需要前面的grep或其他任何东西。

    $ cat file
    dn: uid=test_user_2,ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot
    cn: test_user_2
    uid: test_user_2
    uidNumber: 10000
    gidNumber: 400
    homeDirectory: /home/test_user_2
    userPassword:: e2NyeXB0fSo=
    
    dn: uid=test_user_3,ou=People,fsFragmentId=Security,fsClusterId=ClusterRoot
    cn: test_user_3
    uid: test_user_3
    uidNumber: 500
    gidNumber: 400
    homeDirectory: /home/test_user_2
    userPassword:: e2NyeXB0fSo=
    
    dn: cn=test_group_3,ou=Group,fsFragmentId=Security,fsClusterId=ClusterRoot
    cn: test_group_3
    gidNumber: 10000
    homeDirectory: /home/test_user_3
    userPassword:: e2NyeXB0fSo=
    

    【讨论】:

      猜你喜欢
      • 2015-06-12
      • 1970-01-01
      • 1970-01-01
      • 2013-05-09
      • 2015-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多