我有三个文件:
FILE1.TXT :
XYZ与ABC
DFC什么
FBFBBBFde
warlaugh世界
FILE2.TXT :
XYZ 与 ABC
warlaugh 世界
file3.txt :
XYZ with abc
DFC whatever
FBFBBBF
world of warlaugh
file2.txt
是来自file1.txt
的带空格的已处理文件。 file1.txt
的行与file3.txt
对齐,即foobaristhehelloworld <-> XYZ with abc
。
由于某些原因,处理从file2.txt
丢弃了行,但更重要的是在处理后从file3.txt
检索相应的行。
如何在file2.txt
中检查哪些行已被删除,然后生成如下所示的file4.txt
:
file4.txt :
XYZ with abc
world of warlaugh
我可以用python做到这一点,但我确信sed / awk或bash技巧有一个简单的方法:
with open('file1.txt', 'r') as file1, open('file2.txt') as file2, open('file3.txt', 'r') as file3:
file2_nospace = [i.replace(' ', '') for i in file2.readlines()]
file2_indices = [i for i,j in enumerate(file1.readlines()) if j in file2_nospace]
file4 = [j for i,j in enumerate(file3.readlines()) if i in file2_indices]
open('file4.txt', 'w').write('\n'.join(file4))
如何使用sed / awk / grep或bash技巧创建file4.txt?
答案 0 :(得分:1)
首先删除file2.txt
中的空格,使其行显示为file1.txt
:
sed 's/ //g' file2.txt
然后将其用作与file1.txt
匹配的模式。使用grep -f
命令执行此操作,并使用-n
查看与file2.txt
中构造的模式匹配的file1.txt的行号:
$ grep -nf <(sed 's/ //g' file2.txt) file1.txt
1:XYZ与ABC
4:warlaugh世界
现在您需要删除:
之后的任何字符,以使新模式与file3.txt
行匹配:
$ grep -nf <(sed 's/ //g' file2.txt) file1.txt | sed 's/:.*/:/'
1:
4:
为file3.txt
的每一行添加行号,请使用:
$ nl -s':' file3.txt | sed -r 's/^ +//'
1:XYZ with abc
2:DFC whatever
3:FBFBBBF
4:world of warlaugh
现在您可以将第一个输出用作模式以匹配第二个输出:
$ grep -f <(grep -nf <(sed 's/ //g' file2.txt) file1.txt | sed 's/:.*/:/') <(nl -s':' file3.txt | sed -r 's/^ +//')
1:XYZ with abc
4:world of warlaugh
要删除起始行号,只需使用cut
:
$ grep -f <(grep -nf <(sed 's/ //g' file2.txt) file1.txt | sed 's/:.*/:/') <(nl -s':' file3.txt | sed -r 's/^ +//') | cut -d':' -f2
XYZ with abc
world of warlaugh
最后将结果保存到file4.txt
:
$ grep -f <(grep -nf <(sed 's/ //g' file2.txt) file1.txt | sed 's/:.*/:/') <(nl -s':' file3.txt | sed -r 's/^ +//') | cut -d':' -f2 > file4.txt
答案 1 :(得分:1)
您可以通过一次调用awk来同样地执行此操作:
awk 'FILENAME ~ /file2.txt/ { gsub(/ /, ""); a[$0]; next }
FILENAME ~ /file1.txt/ && $0 in a { b[FNR]; next }
FILENAME ~ /file3.txt/ && FNR in b { print }' file2.txt file1.txt file3.txt
您还可以使用两个awk来避免使用FILENAME
变量:
awk 'FNR==NR { gsub(/ /, ""); a[$0]; next }
$0 in a { print FNR }' file2.txt file1.txt |
awk 'FNR==NR { a[$0]; next } FNR in a { print }' - file3.txt
使用> file4.txt
输出到file4.txt之后。
基本上是
答案 2 :(得分:1)
循环遍历原始文件,并在file2中查找相应的行。 当行匹配时,从file3打印相应的行。
linenr=0
filternr=1
for line in $(cat file1.txt); do
(( linenr = linenr + 1 ))
line2=$(sed -n ${filternr}p file2.txt | cut -d" " -f1)
if [[ "${line}" = ${line2}* ]]; then
(( filternr = filternr + 1 ))
sed -n ${linenr}p file3.txt
fi
done > file4.txt
当文件很大时(实际上当file2中的行数很大时),你想要改变这个解决方案,避免sed每次都要经过file2和file3。写入/覆盖/维护的解决方案不那么简单......
答案 3 :(得分:1)
在每个文件中查看一次可以使用stdin的diff和重定向来完成 此解决方案仅在您确定没有&#39; |&#39; -character时才有效:
#/bin/bash
function mycheck {
if [ -z "${filteredline}" ]; then
exec 0<file2.txt
read filteredline
fi
line2=${filteredline%% *}
if [[ "${line}" = ${line2}* ]]; then
echo ${line} | sed 's/.*|\t//'
read filteredline
if [ -z "${filteredline}" ]; then
break;
fi
fi
}
IFS="
"
for line in $(diff -y file1.txt file3.txt); do
mycheck "${line}"
done > file4.txt