我想在两个文件中找到公共行,并用第二个文件的下一行替换第一个文件的下一行。 Sed,awk,Perl,Bash,欢迎任何解决方案。
比较不区分大小写,并且可能会多次出现同一行。
文件1:
hgacdavd
sndm,ACNMSDC
msgid "Rome"
msgstr ""
kgcksdcgfkdsb
msgid ""
hsdvchgsdvc
msgstr ""
dhshfjksdfhmd
msgid "Vidya"
msgstr ""
sdjhcbnd
dcndnv
cfnkdndvrknvkf
dfkvrnkdfnk
snfvrkng
msgid "Rome"
msgstr ""
wdbhkjbcfj
#dmcdmf
f,nvdf,
fvnfnvk
vfmf,mv
vfn
msgid "vid"
msgstr ""
dmcbdmbcvmfbvmkhsdk
文件2:
dfhkvgjbfrvkf
msgid "Rome"
msgstr "new bie"
sdbsjbcdcbwoido
fjcdcvnm
msgid "vidya"
msgstr "expert"
dvnjfkdvhnkfvnknsbdjh
msgid "vid"
msgstr "newton"
dfenfjdbrfjbvlfnvl
dcnkncvkdfvknfv
fcndkbvknfkv
vfdnkvnfknbvkfn
稍后,文件1应为:
hgacdavd
sndm,ACNMSDC
msgid "Rome"
msgstr "new bie"
kgcksdcgfkdsb
msgid ""
hsdvchgsdvc
msgstr ""
dhshfjksdfhmd
msgid "Vidya"
msgstr "expert"
sdjhcbnd
dcndnv
cfnkdndvrknvkf
dfkvrnkdfnk
snfvrkng
msgid "Rome"
msgstr "new bie"
wdbhkjbcfj
#dmcdmf
f,nvdf,
fvnfnvk
vfmf,mv
vfn
msgid "vid"
msgstr "newton"
dmcbdmbcvmfbvmkhsdk
答案 0 :(得分:1)
在此版本的问题中,msgid和msgstr的行成对出现,并与其他行分隔为空行。对于这种情况,这是一个(长)行解决方案:
$ awk -F'"' 'BEGIN{RS="\n\n";OFS=""} NR==FNR {c[tolower($2)]=$4; next} {print $1,"\"",$2,"\"",$3,"\"",c[tolower($2)],"\"\n"}' file2 file1
msgid "Rome"
msgstr "new bie"
msgid "Vidya"
msgstr "expert"
msgid "Rome"
msgstr "new bie"
msgid "vid"
msgstr "newton"
更多信息:以下版本使用新信息更新file1:
$ awk -F'"' 'BEGIN{RS="\n\n";OFS=""} NR==FNR {c[tolower($2)]=$4; next} {print $1,"\"",$2,"\"",$3,"\"",c[tolower($2)],"\"\n"}' file2 file1 >tmp && mv tmp file1
工作原理:让我们把它分解成几部分。第一部分是设置:
$ awk -F'"' 'BEGIN{RS="\n\n";OFS=""}
要理解上述内容,需要知道awk
将文件分解为“记录”,然后将记录分解为“字段”。上面说过,每当出现一个空白行(连续两个换行符)时,请将后面的内容视为新的“记录”。换句话说,记录分隔符是两个换行符:RS="\n\n"
。它还说应该根据双引号的外观将记录分解为字段:-F'"'
。最后,它说,在打印我们的输出时,不要在我们拥有的东西上添加任何额外的空间。换句话说,输出字段分隔符是空字符串:OFS=""
下一部分是:
... NR==FNR {c[tolower($2)]=$4; next} ...
这表示,在读取给定的第一个文件名(file2
)时,创建一个名为c
的关联数组(如字典)。数组的键是msgid。值是msgstr。因此,c[rome]=new bie
。我们将tolower
应用于msgid,以便所有密钥始终为小写。 next
命令意味着。
上面的NR==FNR
部分可能看起来很模糊。要理解它,需要知道awk
计算它看到的记录数并将该值分配给NR
。它还会计算它从当前正在读取的文件中看到的记录数,并将其分配给FNR
。因此,当我们读取第一个文件时,两者是相等的:NR==FNR
。当awk
开始阅读第二个文件时,NR>FNR
将跳过代码块。
最后一部分是:
... {print $1,"\"",$2,"\"",$3,"\"",c[tolower($2)],"\"\n"}' file2 file1
当我们开始阅读第二个文件(file1
)并且只包含一个print语句时,将执行此部分。它打印msgid行,包括msgid:$1,"\"",$2,"\""
周围的引号。并且,它还打印出msgstr,在我们的关联数组c
中查找msgstr的值并在其周围加上引号,并在结尾添加换行符:"\"",$3,"\"",c[tolower($2)],"\"\n"
。
在此版本中,msgid和msgstr行不一定相邻。因此,每次遇到msgid行时,我们都会将其值保存到变量id
。在浏览file2时,我们查找msgstr行并将其值存储在关联数组c
中。然后,在处理file1时,我们在msgstr行中替换c[id]
:
awk -F'"' 'NR==FNR && $1=="msgid " {id=tolower($2)} NR==FNR && $1=="msgstr " {c[id]=$2} NR==FNR {next} $1=="msgid " {id=tolower($2)} {if ($1=="msgstr ") print "msgstr \"" c[id] "\""; else print $0}' file2 file1 >tmp && mv tmp file1
答案 1 :(得分:0)
这可能适合你(GNU sed):
sed -r '/msgid/{$!N;s|(.*)\n(.*)|/\1/I{n;s/.*/\2/}|}' file2 | sed -rf - file1
将file2
转换为针对file1
运行的sed脚本。
该脚本将以msgid
开头的行和以下行转换为与msgid
匹配的命令,然后打印该行并用脚本文件中的第二行内容替换下一行。
答案 2 :(得分:0)
在这里查看我的源代码! http://localhost/merge_two_po_files/web 通过以下链接连接到主页:... / merge_two_po_files / web(例如:JSFiddle Example)