【问题标题】:Simplify text processing pipeline with awk使用 awk 简化文本处理管道
【发布时间】:2023-04-10 20:57:01
【问题描述】:

我有以下文本数据(高度简化):

dn: cn=config
objectClass: olcGlobal
cn: config
some: properties

dn: cn={0}kerberos,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: {0}kerberos
some: properties
some: junk
some: more junk

dn: olcDatabase={-1}frontend,cn=config
objectClass: olcDatabaseConfig
some: properties

想要的输出是:

dn: cn=kerberos,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: kerberos
some: properties

我编写了以下shell管道来实现这一点:

awk -vRS= -vFS="\n" '/kerberos/{print $0}' /tmp/input.txt | \
    sed 's/{0}kerberos/kerberos/' | \
    sed '/some: junk/,$d'

这很好用,但我觉得混合 awk 和 sed 是在“作弊”。如何使用单个 awk 脚本实现这一点?

【问题讨论】:

    标签: awk sed


    【解决方案1】:

    显然,您只需要一个sed 命令,而不是两个:

    sed -e 's/{0}kerberos/kerberos/' -e '/some: junk/,$d'
    

    除非您坚持使用 C shell,否则行尾的反斜杠是不必要的。

    您可以在一个 sed 命令中完成所有操作:

    sed -n -e '/kerberos/,/^$/{
            s/{0}kerberos/kerberos/
            /some: junk/,$d; p;}' 
    

    s/// 替换后,可以用分号将其展平为一行。

    sed -n -e '/kerberos/,/^$/{ s/{0}kerberos/kerberos/; /some: junk/,$d; p; }' 
    

    在 Mac OS X (BSD) 上,sed 需要 } 之前的分号; GNU sed 很高兴没有它。

    您也可以在awk 中完成所有操作:

    awk '/kerberos/,/^$/ { sub(/\{0\}kerberos/,"kerberos");
                           if ($0 ~ /^some:/ && some++ > 0) next;
                           if ($0 != "") print
                         }' input.txt
    

    对于输入数据,产生:

    dn: cn=kerberos,cn=schema,cn=config
    objectClass: olcSchemaConfig
    cn: kerberos
    some: properties
    

    【讨论】:

    • 您的脚本在我的示例输入中运行良好 - 真实数据集(在 these instructions 中遇到)需要稍微严格的匹配条件。感谢您的精彩帖子,正是我想要的:)
    • 这假设在some: 之后你有junk。我认为 OP 仅意味着要删除的其他数据。所以在这里我会选择awk 而不是sed
    猜你喜欢
    • 1970-01-01
    • 2018-11-25
    • 2019-03-29
    • 1970-01-01
    • 2018-07-29
    • 1970-01-01
    • 2021-07-19
    • 1970-01-01
    • 2012-08-09
    相关资源
    最近更新 更多