Shell 如何提取第二列显示在其他文件中的行?

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]=

我有两份档案。”“数据文件”是一个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]=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
循环是合适的,请参阅。