简体   繁体   English

如何根据匹配模式用另一个文件中的行替换文本文件中的行?

[英]How can I replace lines in a text file with lines from another file based on matching pattern?

I want to replace some lines in a file with lines from another file based on matching a pattern. 我想基于匹配模式用另一个文件中的行替换文件中的某些行。 I want to replace every line that begin with "rolOccupant" after finding "# SBD_ING_USER" to the empty line with content from file x 我想用“#SBD_ING_USER”替换每行以“rolOccupant”开头的行,其中包含来自文件x的内容的空行

File x 档案x

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

Input file 输入文件

# 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

OUTPUT file 输出文件

# 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

awk one-liner awk one-liner

 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= to set empty line as the Record Separator -v RS=将空行设置为记录分隔符

FNR==NR{a=a$0; next} FNR==NR{a=a$0; next} : This will store your File X contents in variable a FNR==NR{a=a$0; next} :这将把你的File X内容存储在变量a

/# SDB_ING_USER/ {gsub(/roleOccupant.*/,a ORS)} : While iterating over your Input file if record contains # SDB_ING_USER then substitute all lines starting from roleOccupant to end of record with a ORS in other words a "\\n" /# SDB_ING_USER/ {gsub(/roleOccupant.*/,a ORS)} :在记录包含# SDB_ING_USER迭代Input file ,然后将从roleOccupant开始的所有行roleOccupant为带有a ORS的记录结尾,换句话说a "\\n"

Output: 输出:

# 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

Using awk 使用awk

One-liner: 一内胆:

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

Better Readable: 更好的可读性:

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

Explanation: 说明:

  • FNR==NR{r=(r!=""?r RS:"")$0;next} This block we read only file1 and save file1 rows in variable r , separated by record separator RS , FNR==NR will be true, only when awk reads first file. FNR==NR{r=(r!=""?r RS:"")$0;next}这个块我们只读取file1并保存变量r file1行,用记录分隔符RS分隔, FNR==NR将是是的,仅当awk读取第一个文件时。

  • /# SDB_ING_USER/{u=1} if line from file2 , contains regexp in /..../ then, set variable u=1 /# SDB_ING_USER/{u=1}如果来自file2行,在/..../包含regexp,则设置变量u=1

  • u && /^roleOccupant:/{next} if variable u is set, and line starts with roleOccupant , skip such line, and go to next record, from file2 u && /^roleOccupant:/{next}如果设置了变量u ,并且行以roleOccupant ,则跳过这样的行,然后从file2转到下一条记录

  • u && !NF{print r; u=""} u && !NF{print r; u=""} if variable u is set, and !NF , meaning empty line ( NF gives no of fields in record, NF=0 means blank line, !0 is 1 , which is true state), then print variable r , and nullify variable u u && !NF{print r; u=""}如果变量u被设置,并且!NF ,意味着空行( NF给出记录中的字段, NF=0表示空行, !01 ,这是真状态),然后打印变量r ,并使变量u无效

  • }1 1 at the end does default operation, thats print current record/row/line, in current context, this default operation takes only if record not skipped in above, statements. 最后的}1 1执行默认操作,即打印当前上下文中的当前记录/行/行,此默认操作仅在上面的语句中未跳过记录时才采用。

file1: 文件1:

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

file2: 文件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

Output: 输出:

$ 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

Where the input file is sdb.txt and file x is x.txt , I use a sed command file cmd.sed to do this: 如果输入文件是sdb.txt而文件x是x.txt ,我使用sed命令文件cmd.sed来执行此操作:

sed -f cmd.sed sdb.txt

sed.cmd : sed.cmd

# Within the section from SDB_ING_USER to a blank line
/SDB_ING_USER/,/^$/{
    # Delete roleOccupant lines
    /roleOccupant/d
    # At the blank line
    /^$/{
        # Read x.txt into the output stream
        r x.txt
        # Append a blank line to the output stream
        a
        # Delete the blank line from the input stream
        # (Prevents a blank line before the x.txt content)
        d
    }
}

This is done with a sed command file rather than as a single line sed command bcause the sed r and a commands require a newline, so they are painful to try to use in a one-liner. 这是用sed命令文件,而不是作为bcause sed的单行sed命令完成ra命令需要一个换行符, 所以他们是痛苦的尝试在一个班轮使用。 (See EDIT below regarding newlines and -e ) (有关换行符和-e请参阅下面的编辑)

Output: 输出:

$ sed -f cmd.sed sdb.txt
# 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

EDIT. 编辑。 Looked at potong's use of e cat which allows reading the x.txt file into the pattern space (rather than output stream) AND realized that at the command line you can just use multiple -e arguments to get effective line breaks in one-liner sed commands. 看看potong对e cat的使用,它允许将x.txt文件读入模式空间(而不是输出流)并意识到在命令行中你可以使用多个-e参数来获得单行sed中的有效换行符命令。

So here's a new one-liner: 所以这是一个新的单行:

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

This might work for you (GNU sed): 这可能适合你(GNU sed):

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

Focus on the lines between SDB_ING_USER and the next empty line. 专注于SDB_ING_USER和下一个空行之间的SDB_ING_USER Delete any lines containing the string roleOccupant and insert file x before the empty line. 删除包含字符串roleOccupant所有行,并在空行之前插入文件x

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM