Shell 如何提取第二列显示在其他文件中的行?
我有两份档案。”“数据文件”是一个csv文件,第二个是“项目文件”,每行中都有一个项目id。我想提取第二列在“项目文件”中的数据行 例如:Shell 如何提取第二列显示在其他文件中的行?,shell,awk,Shell,Awk,我有两份档案。”“数据文件”是一个csv文件,第二个是“项目文件”,每行中都有一个项目id。我想提取第二列在“项目文件”中的数据行 例如: 23,18,4,2,2,2,1,2,1,2,1 26,17,5,4,1,3,1,1,2,2,1 26,18,4,4,1,3,1,2,2,1 26,16,1,3,1,3,1,1,2,2,1 项目清单如下: 十八 二十 输出:第一行和第三行是GNU awk的解决方案: awk 'BEGIN{FS=OFS=","} ARGIND==1{items[$1]=
- 23,18,4,2,2,2,1,2,1,2,1
- 26,17,5,4,1,3,1,1,2,2,1
- 26,18,4,4,1,3,1,2,2,1
- 26,16,1,3,1,3,1,1,2,2,1
- 十八
- 二十
输出:第一行和第三行是GNU awk的解决方案:
awk 'BEGIN{FS=OFS=","} ARGIND==1{items[$1]=1} ARGIND==2 {if (items[$2]) print;}' "item file" "Data file"
argid
表示命令行参数编号,此处表示文件位置
可以简化为:
awk 'BEGIN{FS=",";RS="\r?\n"} ARGIND==1{items[$1]=1} ARGIND==2 && items[$2]' "item file" "Data file"
感谢@karakfa和@EdMorton提供的这些改进点。这些是GNU awk的解决方案:
awk 'BEGIN{FS=OFS=","} ARGIND==1{items[$1]=1} ARGIND==2 {if (items[$2]) print;}' "item file" "Data file"
argid
表示命令行参数编号,此处表示文件位置
可以简化为:
awk 'BEGIN{FS=",";RS="\r?\n"} ARGIND==1{items[$1]=1} ARGIND==2 && items[$2]' "item file" "Data file"
感谢@karakfa和@EdMorton的这些改进点。同样的逻辑可以写成
$ awk 'NR==FNR{a[$1]; next} $2 in a' itemlist FS=, data
同样的逻辑可以写成
$ awk 'NR==FNR{a[$1]; next} $2 in a' itemlist FS=, data
下面是Perl解决方案
/tmp> cat data.csv
23,18,4,2,2,2,1,2,1,2,1
26,17,5,4,1,3,1,1,2,2,1
26,18,4,4,1,3,1,2,2,2,1
26,16,1,3,1,3,1,1,2,2,1
/tmp> cat item.lst
18
20
/tmp> perl -lne ' $kv{$_}++ if $ARGV eq "item.lst"; /,(\S+?),/ and $kv{$1} and print ' item.lst data.csv
23,18,4,2,2,2,1,2,1,2,1
26,18,4,4,1,3,1,2,2,2,1
/tmp>
更可读的格式
/tmp> perl -lne ' if($ARGV eq "item.lst") { $kv{$_}++ }; if( $ARGV eq "data.csv") { print if /,(\S+?),/ and $kv{$1} } ' item.lst data.csv
23,18,4,2,2,2,1,2,1,2,1
26,18,4,4,1,3,1,2,2,2,1
/tmp>
下面是Perl解决方案
/tmp> cat data.csv
23,18,4,2,2,2,1,2,1,2,1
26,17,5,4,1,3,1,1,2,2,1
26,18,4,4,1,3,1,2,2,2,1
26,16,1,3,1,3,1,1,2,2,1
/tmp> cat item.lst
18
20
/tmp> perl -lne ' $kv{$_}++ if $ARGV eq "item.lst"; /,(\S+?),/ and $kv{$1} and print ' item.lst data.csv
23,18,4,2,2,2,1,2,1,2,1
26,18,4,4,1,3,1,2,2,2,1
/tmp>
更可读的格式
/tmp> perl -lne ' if($ARGV eq "item.lst") { $kv{$_}++ }; if( $ARGV eq "data.csv") { print if /,(\S+?),/ and $kv{$1} } ' item.lst data.csv
23,18,4,2,2,2,1,2,1,2,1
26,18,4,4,1,3,1,2,2,2,1
/tmp>
请将该示例输入的所需输出添加到您的问题中。仅在本网站上就被询问和回答了数百次。搜索档案2分钟,你就会找到它。请将你想要的输入样本的输出添加到你的问题中。仅在这个网站上就被询问和回答了数百次。搜索档案2分钟,你就会找到它。
{if(x)print}
可以简单地写成x
@EdMorton这是什么意思?@EdMorton知道了,没错。我确实创建了用于在windows上测试的文件。我经常在批处理文件中使用gawk,所以我知道这些奇怪的引用规则。现在我倾向于先打开bash,然后测试这些…{if(x)print}
可以简单地写成x
@EdMorton这是什么意思?@EdMorton明白了,没错。我确实创建了用于在windows上测试的文件。我经常在批处理文件中使用gawk,所以我知道这些奇怪的引用规则。现在我倾向于先打开bash,然后测试这些…@Tiw;这是一个惯用的解决方案,仅在这个网站上就可以回答数百个问题,不需要解释。@EdMorton我不喜欢NR==FNR
,因为当第一个文件为空时,它会处理错误。我没有意识到,argid
是GNU awk唯一的特性。然后使用FILENAME==ARGV[1]
进行移植。但是,如果/当同一个文件在命令行中包含两次时(例如,对于两次通过的解决方案),则该操作将失败。@EdMorton是否有其他方法可以避免这些陷阱?感谢您的建议:)是的,但它涉及到开始部分的处理,其中包括将文件名与可能与文件名混合在一起的变量设置分离,因此这不是一件小事,或者在某些情况下,在开始部分使用一个,而getline
循环是合适的,请参阅。@Tiw;这是一个惯用的解决方案,仅在这个网站上就可以回答数百个问题,不需要解释。@EdMorton我不喜欢NR==FNR
,因为当第一个文件为空时,它会处理错误。我没有意识到,argid
是GNU awk唯一的特性。然后使用FILENAME==ARGV[1]
进行移植。但是,如果/当同一个文件在命令行中包含两次时(例如,对于两次通过的解决方案),则该操作将失败。@EdMorton是否有其他方法可以避免这些陷阱?感谢您的建议:)是的,但它涉及开始部分中的处理,其中包括将文件名与可能与文件名混合的变量设置分离,因此这不是一件小事,或者在某些情况下使用,而开始部分中的getline
循环是合适的,请参阅。