提问人:Dexter0015 提问时间:8/22/2023 最后编辑:Dexter0015 更新时间:8/31/2023 访问量:128
AWK:按第一列匹配两个文件不起作用
AWK : matching two files by first column doesn't work
问:
我使用 awk 几乎没有问题,它开始给我白发..
我有两个内容不同的文件,但第一列值是相同的。
文件在脚本期间以 csv 文件(分号分隔)和 lokks 的形式生成,如下所示:
main_file.csv
---
151597-21;151597;21;3;15;;"Vente OK";excluded
151598-21;151598;21;3;15;;"Vente OK";excluded
151599-0;151599;0;0;10;;;programmed
151600-0;151600;0;0;10;;;programmed
151601-0;151601;0;0;10;;;programmed
151602-0;151602;0;0;10;;;programmed
151603-0;151603;0;0;10;;;programmed
151604-0;151604;0;0;10;;;programmed
151605-0;151605;0;0;10;;;programmed
151606-0;151606;0;0;10;;;programmed
151607-0;151607;0;0;10;;;programmed
...
151622-0;151622;0;0;10;;;programmed
151623-0;151623;0;0;10;;;programmed
151624-0;151624;0;0;10;;;programmed
151625-0;151625;0;0;10;;;programmed
...
filter_file.csv
---
151622-0;151622;0
我想比较这两个文件,并使用第一列值作为比较,创建第三个文件,其中包含与“filter_file.csv”中的行匹配的“main_file.csv”中的行。
如示例所示,我应该得到一个包含一行的“result_file.csv”,不幸的是我得到一个空文件。
专业输出应为:
151622-0;151622;0;0;10;;;programmed
这是我尝试过的通讯:
awk 'BEGIN {FS=OFS=";"} NR==FNR{a[$1]=1; next} a[$1]{print}' filter_file.csv main_file.csv > result_file.csv
如果我理解正确,它应该这样解释:
awk ' # starting awk program
BEGIN {FS=OFS=";"} # define column separator as commat for both files (main & filter)
NR==FNR{a[$1]=1; next} # during read of the first file (filter_file.csv), create an array 'a' with first column value as index
a[$1]{print} # during read of the second file (main_file.csv), if first column value exist as an index of the array 'a', print the whole line in the 'result_file.csv'
'
filter_file.csv main_file.csv # files to be compared
> result_file.csv # direct the output to the third file
但恐怕我错过了一些东西:/
编辑:更新以添加一些上下文:
该命令是从 PHP 脚本执行的,如下所示:
$awk_cmd = 'awk \'BEGIN {FS=OFS=";"} NR==FNR {a[$1]=1; next} $1 in a {print}\' ' . $filter_file . ' ' . $ref_file . ' > ' . $match_file;
exec($awk_cmd);
其中 $filter_file、$ref_file 和 $match_file 是文件的完整路径。
EDIT2 :我测试了grep命令并得到以下输出:
0000000 1 5 1 6 2 2 - 0 ; 1 5 1 6 2 2 ;
0000020 0 ; 0 ; 1 0 ; ; ; p r o g r a m
0000040 m e d \r \n
0000045
答:
您的文件格式显然是 DOS (),但这在这里应该不是问题。下面假设您的 csv 文件是简单的文件(没有多行记录,没有带引号的字段......示例输出以 为前缀。\r\n
;
-|
使用任何 POSIX :awk
awk -F';' 'NR==FNR {a[$1];next} $1 in a' filter_file.csv main_file.csv
-| 151622-0;151622;0;0;10;;;programmed
-F';'
定义为输入字段分隔符。在解析第一个文件时(仅对第一个文件为 true),将第一个字段 () 存储为数组的键并移动到行。在解析第二个文件时,如果第一个字段是数组 () 的键,则打印该行(默认操作)。;
NR==FNR
$1
a
next
a
$1 in a
您还可以使用 和 :sort
join
join -t';' -o 1.{1..8} <( sort -t';' main_file.csv ) <( sort -t';' filter_file.csv )
-| 151622-0;151622;0;0;10;;;programmed
评论
\r\n
\n
awk
首先感谢大家的建议!
我自言自语,因为没有一个答案完全解决了这个问题,尽管完整的解决方案是@shelter编码建议和@Renaud Pacalet 重写 awk 命令之间的混合。
我在问题中没有指定的东西(因为当时我没有,尽管它会产生任何影响)是我在 Windows 10 上的本地环境中测试了代码,这是问题的一部分,正如@shelter建议的那样......
因此,在执行 awk 命令之前,我在代码中添加一个步骤来转换要比较的文件:
dos2unix filter_file.csv main_file.csv
我还修改了 Pacalet 建议@Renaud为 awf 指定列分隔符的方式(而不是 ,它给了我以下命令:
awk -F';' 'NR==FNR {a[$1]=1; next} $1 in a {print}' filter_file.csv main_file.csv > result_file.csv
这两个变化结合在一起给了我正确的结果。
在我的 php 脚本中,它给出了如下内容:
$convert = 'dos2unix ' . $filter_file . ' ' . $ref_file;
exec($convert);
$awk_cmd = 'awk -F\';\' \'NR==FNR {a[$1]=1; next} $1 in a {print}\' ' . $filter_file . ' ' . $ref_file . ' > ' . $match_file;
exec($awk_cmd);
其中使用变量调用文件,因为它包含它的完整路径。
一旦应用了这些 chonges,一切都在我的本地服务器上工作,但是,一个推送到测试服务器 (ubuntu) 我们仍然收到错误。 原来 dos2unix 没有安装在测试服务器上...... Onece 已安装,一切按预期工作。
不过,我不明白为什么我只在过滤器文件只计算一行时才遇到这个问题。当过滤器文件计数几行时,我从未提出过这个问题,奇怪......
评论
a[$1]{print}
$1 in a
a[]
dos2unix filter_file.csv main_file.csv
\n