比较2个文件并删除file2中与file1中找到的值匹配的任何行

时间:2012-04-18 13:09:23

标签: python bash sed awk grep

我有两个文件。我试图删除文件2中的任何行,当它们匹配file1中找到的值。一个文件有这样的列表:

File1中

ZNI008
ZNI009
ZNI010
ZNI011
ZNI012

......超过19463行

第二个文件包含与第一个中列出的项匹配的行: file2的

copy /Y \\server\foldername\version\20050001_ZNI008_162635.xml \\server\foldername\version\folder\
copy /Y \\server\foldername\version\20050001_ZNI010_162635.xml \\server\foldername\version\folder\
copy /Y \\server\foldername\version\20050001_ZNI012_162635.xml \\server\foldername\version\folder\
copy /Y \\server\foldername\version\20050001_ZNI009_162635.xml \\server\foldername\version\folder\

...继续列出直到第51360行

到目前为止我尝试过:

grep -v -i -f file1.txt file2.txt > f3.txt

不会向f3.txt生成任何输出或删除任何行。我通过运行验证

wc -l file2.txt

,结果是

51360 file2.txt

我相信原因是没有确切的匹配。当我运行以下内容时,它什么都没有显示

comm -1 -2 file1.txt file2.txt

正在运行

( tr '\0' '\n' < file1.txt; tr '\0' '\n' < file2.txt ) | sort | uniq -c | egrep -v '^ +1'

只显示一场比赛,即使我可以清楚地看到有多场比赛。

或者将所有数据放入一个文件并运行以下内容:

grep -Ev "$(cat file1.txt)" 1>LinesRemoved.log

说论证有太多的线要处理。

我需要从file2中删除与file1中的项匹配的行。

我也在python中尝试这个:  `

    #!/usr/bin/python
s = set()

# load each line of file1 into memory as elements of a set, 's'
f1 = open("file1.txt", "r")
for line in f1:
    s.add(line.strip())
f1.close()

# open file2 and split each line on "_" separator,
# second field contains the value ZNIxxx
f2 = open("file2.txt", "r")
for line in f2:
    if line[0:4] == "copy":
        fields = line.split("_")
        # check if the field exists in the set 's'
        if fields[1] not in s:
            match = line
        else:
            match = 0
    else:
        if match:
            print match, line,

`

它不能正常工作..因为我越来越好 '追溯(最近的呼叫最后):   文件“./test.py”,第14行,在?     如果字段[1]不在s中: IndexError:列表索引超出范围'

4 个答案:

答案 0 :(得分:7)

怎么样:

grep -F -v -f file1 file2 > file3

答案 1 :(得分:0)

由于-i开关

,这是使用 Bash GNU sed
cp file2 file3
while read -r; do
    sed -i "/$REPLY/d" file3
done < file1

肯定有更好的方法,但这里是-i的黑客攻击:D

cp file2 file3
while read -r; do
    (rm file3; sed "/$REPLY/d" > file3) < file3
done < file1

这会利用shell评估顺序


好吧,我猜这个想法的正确方法是使用ed。这也应该是POSIX。

cp file2 file3
while read -r line; do
    ed file3 <<EOF
/$line/d
wq
EOF
done < file1

在任何情况下,grep似乎都是适合这项工作的工具 @byrondrossos答案应该对你有用;)

答案 2 :(得分:0)

这无疑是丑陋的,但确实有效。但是,所有的路径必须相同(当然除了ZNI ###部分)。除了路径的ZNI ###之外的所有内容都被删除,因此命令grep -vf可以在已排序的文件上正确运行。

首先将“testfile2”转换为“testfileconverted”以显示ZNI ###

cat /testfile2 | sed 's:^.*_ZNI:ZNI:g' | sed 's:_.*::g' > /testfileconverted

第二次使用转换后的文件的反grep与“testfile1”相比,并将重新格式化的输出添加到“testfile3”

bash -c 'grep -vf <(sort /testfileconverted) <(sort /testfile1)' | sed "s:^:\copy /Y \\\|server\\\foldername\\\version\\\20050001_:g" | sed "s:$:_162635\.xml \\\|server\\\foldername\\\version\\\folder\\\:g" | sed "s:|:\\\:g" > /testfile3

答案 3 :(得分:0)

我更喜欢byrondrossos的grep解决方案,但这是另一种选择:

sed $(awk '{printf("-e /%s/d ", $1)}' file1) file2 > file3