【问题标题】:How can I replace lines in a text file with lines from another file based on matching pattern?如何根据匹配模式将文本文件中的行替换为另一个文件中的行?
【发布时间】:2017-10-19 21:34:05
【问题描述】:

我想根据匹配模式将文件中的某些行替换为另一个文件中的行。 我想在找到后替换以“rolOccupant”开头的每一行 "#SBD_ING_USER" 到包含文件 x 内容的空行

档案 x

roleOccupant: uid1
roleOccupant: uid2
roleOccupant: uid45
roleOccupant: uid80

输入文件

# SDB_ING_USER
objectClass: organizationalRole
objectClass: top
cn: SDB_ING_USER
description: SDB Ing User Role
roleOccupant: uid1
roleOccupant: uid7
roleOccupant: uid67

# SDB_REGISTERY_USER: 
objectClass: organizationalRole
objectClass: top
cn: SDB_REGISTRY_USER
description: SDB Registry Admin Role
roleOccupant: uid2
roleOccupant: uid34
roleOccupant: uid15

输出文件

# SDB_ING_USER
objectClass: organizationalRole
objectClass: top
cn: SDB_ING_USER
description: SDB Ing User Role
roleOccupant: uid1
roleOccupant: uid2
roleOccupant: uid45
roleOccupant: uid80

# SDB_REGISTERY_USER: 
objectClass: organizationalRole
objectClass: top
cn: SDB_REGISTRY_USER
description: SDB Registry Admin Role
roleOccupant: uid2
roleOccupant: uid34
roleOccupant: uid15

【问题讨论】:

    标签: shell awk sed


    【解决方案1】:

    awk单行

     awk -v RS= -v ORS='\n\n' 'NR==FNR{a=$0;next} /SDB_ING_USER/{sub(/roleOccupant.*/,""); $0=$0 a} 1' fileX file 
    

    -v RS= 设置空行作为记录分隔符

    FNR==NR{a=a$0; next} :这会将您的 File X 内容存储在变量 a

    /# SDB_ING_USER/ {gsub(/roleOccupant.*/,a ORS)} :在遍历您的 Input file 时,如果记录包含 # SDB_ING_USER,则将所有从 roleOccupant 开始的行替换为 a ORS 的记录结尾,换句话说 a "\n"

    输出:

    # SDB_ING_USER
    objectClass: organizationalRole
    objectClass: top
    cn: SDB_ING_USER
    description: SDB Ing User Role
    roleOccupant: uid1
    roleOccupant: uid2
    roleOccupant: uid45
    roleOccupant: uid80
    
    # SDB_REGISTERY_USER:
    objectClass: organizationalRole
    objectClass: top
    cn: SDB_REGISTRY_USER
    description: SDB Registry Admin Role
    roleOccupant: uid2
    roleOccupant: uid34
    roleOccupant: uid15
    

    【讨论】:

      【解决方案2】:

      这可能对你有用(GNU sed):

      sed '/SDB_ING_USER/,/^\s*$/!b;/roleOccupant/d;/^\s*$/e cat x' file
      

      关注SDB_ING_USER 和下一个空行之间的行。删除所有包含字符串roleOccupant 的行,并在空行之前插入文件x

      【讨论】:

        【解决方案3】:

        使用awk

        单线:

        awk 'FNR==NR{r=(r!=""?r RS:"")$0;next}/# SDB_ING_USER/{u=1}u && /^roleOccupant:/{next}u && !NF{print r; u=""}1;END{if(u)print r}' file1 file2
        

        更好的可读性:

        awk '
             FNR==NR{
                  r=(r!=""?r RS:"")$0;
                  next
             }
             /# SDB_ING_USER/{
                  u=1
             }
             u && /^roleOccupant:/{
                 next
            }
            u && !NF{
                 print r; 
                 u=""
            }1
            END{
                 if(u)print r
            }
            ' file1 file2
        

        说明:

        • FNR==NR{r=(r!=""?r RS:"")$0;next}这个块我们只读取file1并将file1行保存在变量r中,由记录分隔符RS分隔,FNR==NR才会为真,只有当awk读取第一个文件时.

        • /# SDB_ING_USER/{u=1} 如果来自file2 的行,在/..../ 中包含正则表达式,则设置变量u=1

        • u && /^roleOccupant:/{next} 如果设置了变量u,并且行以roleOccupant 开头,则跳过该行,并从file2 转到下一条记录

        • u && !NF{print r; u=""} 如果变量u 被设置,!NF 表示空行(NF 给出记录中的字段数,NF=0 表示空行,!01 ,即为真状态),然后打印变量r,并取消变量u

        • }1 1 最后执行默认操作,即打印当前记录/行/行,在当前上下文中,此默认操作仅在上述语句中未跳过记录时才执行。

        文件 1:

        $ cat file1
        roleOccupant: uid1
        roleOccupant: uid2
        roleOccupant: uid45
        roleOccupant: uid80
        

        文件2:

        $ cat file2
        # SDB_ING_USER
        objectClass: organizationalRole
        objectClass: top
        cn: SDB_ING_USER
        description: SDB Ing User Role
        roleOccupant: uid1
        roleOccupant: uid7
        roleOccupant: uid67
        
        # SDB_REGISTERY_USER: 
        objectClass: organizationalRole
        objectClass: top
        cn: SDB_REGISTRY_USER
        description: SDB Registry Admin Role
        roleOccupant: uid2
        roleOccupant: uid34
        roleOccupant: uid15
        

        输出:

        $ awk 'FNR==NR{r=(r!=""?r RS:"")$0;next}/# SDB_ING_USER/{u=1}u && /^roleOccupant:/{next}u && !NF{print r; u=""}1;END{if(u)print r}' file1 file2
        # SDB_ING_USER
        objectClass: organizationalRole
        objectClass: top
        cn: SDB_ING_USER
        description: SDB Ing User Role
        roleOccupant: uid1
        roleOccupant: uid2
        roleOccupant: uid45
        roleOccupant: uid80
        
        # SDB_REGISTERY_USER: 
        objectClass: organizationalRole
        objectClass: top
        cn: SDB_REGISTRY_USER
        description: SDB Registry Admin Role
        roleOccupant: uid2
        roleOccupant: uid34
        roleOccupant: uid15
        

        【讨论】:

          【解决方案4】:

          输入文件是sdb.txt,文件x是x.txt,我使用sed命令文件cmd.sed来做到这一点:

          sed -f cmd.sed sdb.txt

          sed.cmd

          # 从 SDB_ING_USER 到空行的部分内 /SDB_ING_USER/,/^$/{ # 删除roleOccupant行 /roleOccupant/d # 在空白行 /^$/{ # 将 x.txt 读入输出流 r x.txt # 在输出流中添加一个空行 一个 # 从输入流中删除空行 #(防止x.txt内容前出现空行) d } }

          这是通过 sed 命令文件而不是单行 sed 命令来完成的,因为 sed ra 命令需要换行符,因此尝试在单行中使用它们会很痛苦.(有关换行符和-e,请参阅下面的编辑)

          输出:

          $ sed -f cmd.sed sdb.txt # SDB_ING_USER objectClass: 组织角色 对象类:顶部 cn: SDB_ING_USER 描述:SDB Ing 用户角色 角色占用者:uid1 角色占用者:uid2 角色占用:uid45 角色占用:uid80 # SDB_REGISTERY_USER: objectClass: 组织角色 对象类:顶部 cn: SDB_REGISTRY_USER 描述:SDB Registry 管理员角色 角色占用者:uid2 角色占用者:uid34 角色占用:uid15

          编辑。查看 potong 对 e cat 的使用,它允许将 x.txt 文件读入模式空间(而不是输出流),并意识到在命令行中您可以使用多个 -e 参数来获得有效的换行符 -线性 sed 命令。

          所以这是一个新的单行:

          sed -e '/SDB_ING_USER/,/^$/{' -e '/roleOccupant/d' -e '/^$/e cat x.txt' -e '}' sdb.txt

          【讨论】:

            猜你喜欢
            • 2019-02-20
            • 2012-06-05
            • 2013-06-17
            • 2013-06-23
            • 2013-06-23
            • 2021-09-30
            • 1970-01-01
            • 1970-01-01
            • 2013-08-29
            相关资源
            最近更新 更多