按特定顺序匹配来自两个文件和输出字段的字符串

问题描述 投票:1回答:5

我有以下两个文件。

query.txt

pumpkin
kiwi

subject.tsv

kiwifruit   something   green
melon   something   red
pumpkinhead something   orange

如果subject.tsv中的任何第一个字段包含该行,我想循环遍历query.txt并检查每一行。如果是,则应将标签加上subject.tsv中的第三个字段添加到该行。 query.txt中的行的顺序应保留在输出中。

我尝试了以下内容。

while read query; do echo -e $query"\t"; awk '$1 ~ "$query" {print $3}' subject.tsv; done < query.txt

期望的输出:

pumpkin orange
kiwi    green

实际产量:

pumpkin
kiwi
bash awk
5个回答
2
投票

Bash不对单引号(')中公开的字符串执行变量扩展,因此脚本的问题在于:

'$1 ~ "$query" {print $3}'

必须是这样的:

'$1 ~ '"$query"' {print $3}'

但是,即使在修复之后,您的脚本仍然效率低下且容易出错。所以我建议你在一个像这样的awk调用中这样做:

awk -F'\t' -v OFS='\t' '
NR==FNR { a[$0] = $3; next } {
    for (b in a) {
        if (index(b, $0)) {
            print $0, a[b]
            break
        }
    }
}' subject.tsv query.txt

1
投票

虽然问题中缺少很多信息,比如查询文件是否包含唯一字符串?或主题文件包含重复的字符串?但鉴于当前的文件和要求,请在下面给出答案,因为它是基于awk的,它也应该适用于大文件:

awk ' BEGIN{OFS="\t"}
    FILENAME ~ /subject.tsv$/ {
      color[$1]=$3
    }
    FILENAME ~ /query.txt$/ {
      for (i in color) {
      if ( i ~ $1 ) print $1, color[i]
    }
 }'  subject.tsv query.txt

以下是输出:

    pumpkin orange
    kiwi    green

0
投票

在使用while的代码版本中,您需要使用awk选项将要搜索的字符串传递给-v命令,否则awk会将所有字符串视为纯字符串。

例如,如果要传递变量query包含的字符串'pumpkin',则需要执行以下操作:

query="pumpkin"; awk -v query=$query '$1 ~ query' subject.tsv

-v这里用于声明一个使用awk之外的变量内容的变量。你可以看到awk的解释

-v var = val --assign var = val 在程序开始执行之前,将值val分配给变量var。这些变量值可用于AWK程序的BEGIN规则。

因此,您可以尝试通过将query传递给awk来相应地修改您的代码。


0
投票

这是一个bash解决方案

while read pattern; do
    column1=$(cut -d " " -f1 subject.tsv | grep "$pattern")
    allcolumns=$(echo "$pattern $(grep $column1 subject.tsv)")
    echo $allcolumns | cut -d " " -f1,4
done < query.txt

说明

阅读query.txt的所有行

while read pattern; do
   ...
done < query.txt

在column1中查找searchpattern

while read pattern; do
   column1=$(cut -d " " -f1 subject.tsv | grep "$pattern") 
   echo $column1
done < query.txt

产量

pumpkinhead
kiwifruit

使用来自subject.tsv的匹配从query.txt合并模式

while read pattern; do
    column1=$(cut -d " " -f1 subject.tsv | grep "$pattern")
    allcolumns=$(echo "$pattern $(grep $column1 subject.tsv)")
    echo $allcolumns
done < query.txt

产量

pumpkin pumpkinhead something orange
kiwi kiwifruit something green

从合并中提取第一个和最后一个字段

echo $allcolumns | cut -d " " -f1,4

产量

pumpkin orange
kiwi green

0
投票

您可以尝试使用此命令行Perl

$ perl -lane ' BEGIN { open($fh,"query.txt");@q=<$fh>;chomp(@q) } @s=/(\S+)/g; 
    /$q[0]/ and print "$q[0] $s[2]"; if(eof) { close($ARGV); shift @q}; ' subject.tsv subject.tsv

与您的输入。

$ perl -lane ' BEGIN { open($fh,"query.txt");@q=<$fh>;chomp(@q) } @s=/(\S+)/g; 
     /$q[0]/ and print "$q[0] $s[2]"; if(eof) { close($ARGV); shift @q}; ' subject.tsv subject.tsv

pumpkin orange
kiwi green

$
热门问题
推荐问题
最新问题