我搜索过类似的答案,但没有解决部分匹配问题。模式文件是 file2,要删除的行位于 file1.csv 中,这是一个相当大的文件,其列数比此处显示的列多得多。
我在 file1.csv 中有以下字段:
更新:
Linking page,Last crawled
https://start.me/discover/be/entertainment/betting?locale=ro,"Nov 17, 2018"
https://imgcop.com/img/Bwin-Mobile-App-77898390/,"Nov 17, 2018"
https://start.me/site/unibet.be?locale=fr,"Nov 17, 2018"
https://poker.partypoker402.com/en/blog/matt-savage-talks-wpt500.html,"Nov 17, 2018"
文件2包含:
https://roulette2.tk
paradisebingo.t
paradisebingo.tm
free-bwin.ro
sb288.co
OUTPUT
Linking page,Last crawled
Linking page,Last crawled
Linking page,Last crawled
Linking page,Last crawled
Linking page,Last crawled
https://start.me/discover/be/entertainment/betting?locale=ro,"Nov 17, 2018"
https://start.me/discover/be/entertainment/betting?locale=ro,"Nov 17, 2018"
https://start.me/discover/be/entertainment/betting?locale=ro,"Nov 17, 2018"
https://start.me/discover/be/entertainment/betting?locale=ro,"Nov 17, 2018"
https://start.me/discover/be/entertainment/betting?locale=ro,"Nov 17, 2018"
etc....
输出正在重复。我不确定出了什么问题。
awk 'FNR == NR{ neg[$1]; next } { for ( i in neg ) if ( $1 !~ i) print }' file2.txt FPAT='([^,]*)|("[^"]+")' file1.csv > out.csv
但无法让它发挥作用。由于某些奇怪的原因 grep 失败:
grep -vwF -f file2 file1.csv > output.csv
答案1
您所做的看起来是一个不错的尝试,但是正则表达式匹配的子句并没有按照您想要的方式工作。在$2 !~ neg[$1]
中file1
,您尝试查找 的值,neg['156398439']
因为$1
将从第二个文件中检索 ,并且不是首先。所以你的条件永远不会匹配。
您可以执行如下操作,file1
通过循环在操作部分内进行正则表达式比较
awk 'FNR == NR { neg[$1]; next }{ for ( i in neg ) if ( $2 !~ i) print }' file2 FS="," file1
另外,我认为FS
不能采用如此复杂的正则表达式来对 CSV 文件进行去限制,请记住FS
定义要拆分的去限制符,而不是定义如何定义字段。您似乎有一个表达式可以解释该字段应该是什么样子。 GNUawk
允许另一个变量FPAT
来定义这样的正则表达式。
您可以使用
awk 'FNR == NR { neg[$1]; next }{ for ( i in neg ) if ( $2 !~ i) print }' file2 FPAT='([^,]*)|("[^"]+")' file1
答案2
伊尼安的回答file2
当只有一行长时,效果很好,并且是一个更通用的答案的良好开端。但我相信
awk 'FNR == NR { neg[$1]; next } { ok=1; for (i in neg) if ($2 ~ i) ok=0; if (ok) print }' file2 FS="," file1
一般来说会做你想做的事。就像您的答案一样,它首先读取file2
其内容(您想要从中删除的模式file
)并将其存储在数组中。就像 Inian 的答案一样,它是这样的file1
。对于 中的每一行file1
,它循环遍历 中的模式file2
。我们假设线路没问题;如果它与任何模式匹配,那么就不行。如果检查完所有图案后仍然没问题,我们就打印它。
但我把它作为和FS=","
之间的一个论点, 只是因为 Inian 就是这样做的。什么都没关系file2
file1
F产量s我们在阅读时使用的分隔符file2
,只要它不出现在其中 - 并且file2
不包含逗号。因此,我们可以通过以“正常”方式指定字段分隔符来稍微简化上述内容 --F
在命令开头添加一个选项:
awk-F,'FNR == NR { 负[$1];下一个} { 确定=1; for (i in neg) if ($2 ~ i) ok=0;如果(确定)打印}' file2 file1
-F","
如果您愿意,可以使用;它们是等价的。
该测试FNR == NR
是如此流行和普遍,以至于我们不假思索地使用它。
FNR
是行号(又名记录号)在当前文件中,
是NR
行号跨所有输入。 所以,举例来说,
$ cat cats
Felix
Garfield
Heathcliff
$ cat dogs
Lassie
Marmaduke
Snoopy
$ awk '{ print FNR, NR, $0 }' cats dogs
1 1 Felix
2 2 Garfield
3 3 Heathcliff
1 4 Lassie
2 5 Marmaduke
3 6 Snoopy
… 因此 和FNR
对于NR
要处理的第一个文件的每一行都是相等的,而不是在后续文件中。因此我们用来FNR == NR
测试是否正在处理第一个文件。
但这实际上是一种不好的做法。如果第一个文件为空怎么办?
$ cat unicorns
$ wc unicorns
0 0 0 unicorns
$ awk '{ print FNR, NR, $0 }' unicorns dogs
1 1 Lassie
2 2 Marmaduke
3 3 Snoopy
FNR == NR
是真的对于第一个文件确实有数据。 如果你的file2
意志永远不会是空的,你也许可以忽略这个问题。但是,根据问题的定义,如果file2
为空,则输出应该全部为file1
,因为我们没有删除任何内容。但是,如果你用空运行上面的命令file2
,你会得到不 输出,因为当它实际读取第二个文件 ( ) 时,awk
它认为它正在读取第一个文件 ( )。file2
file1
更安全的方法是在文件参数之间进行赋值:
awk -F, '文件!= 2{ 负[$1];下一个} { 确定=1; for (i in neg) if ($2 ~ i) ok=0;如果(确定)打印}'文件2文件=2文件1
这个问题有点模棱两可。 “部分匹配”是什么意思,确切地?伊尼安选择按照问题所暗示的意义来解释它——比如 grep
。如果任何值file2
与第二列的值匹配 file1
作为正则表达式,
然后删除该行 file1
。但这有两个问题。
令人惊讶的因素。我获取了问题中的文件并添加了
154376352,"http://sb288eco.tm","example4"
线路到
file1
,并运行我的第一个命令。该"example4"
行未输出,因为sb288.co
(fromfile2
),被视为正则表达式(其中.
表示“匹配任何字符”),matchedsb288eco
。如果这就是您想要并期望发生的事情,那么您最好现在就停止阅读本文。
- 正则表达式处理的计算成本很高。必须解析和处理正则表达式。这可能比简单的字符串比较花费更多的时间。
我们可以通过测试是否可以解决上述两个问题细绳from存在于 awk 函数的file2
值 from 中:file1
index
awk -F, 'FILE != 2 { neg[$1];下一个} { 确定=1;对于(i 为负数)如果(索引($2,i)> 0)好的=0; if (ok) print }' file2 FILE=2 file1
综上所述,一个.
在file2
比赛中只有一个.
中file1
,而不是任何其他字符。我邀请您在您的数据上测试上述内容,看看它是否更快。
PS 我刚刚注意到自从我发布答案以来您更改了文件格式。最初您想要测试来自的值与 file2
来自的值第二的专栏 file1
。现在您似乎想要测试来自第一的的专栏 file1
。为了适应这一更改,您应该采用$2
与进行比较的任何上述答案的部分i
,并将其更改为使用$1
。或者,如果您确实想测试 的整行 file1
,请使用$0
.
所以,底线,你可能想使用
awk -F, 'FILE != 2 { neg[$1]; next } { ok=1; for (i in neg) if (index($1,i) > 0) ok=0; if (ok) print }' file2 FILE=2 file1
作为你的命令。为了便于阅读,换行符是
awk -F, 'FILE != 2 { neg[$1]; next }
{
ok=1
for (i in neg)
if (index($1,i) > 0) ok=0
if (ok) print
}' \
file2 FILE=2 file1