如何将 cut 的输出通过管道传递给 foreach 命令?

如何将 cut 的输出通过管道传递给 foreach 命令?

我有我想要的剪切命令,它可以抓取文件每一行中的第一个单词。然后我想将 cut 命令中的每个单词放入 foreach 中。然后,我想在 foreach 的主体内执行 grep 命令,以 grep 查找另一个文件中的该单词。

像这样的东西:

@array = (cut /tmp/10218.after -f1); 
foreach $word (@lines) { 
   grep $word /tmp/10218.before;
} 

显然 @array 赋值不起作用。我该如何解决这个问题?

我确信有很多方法我只是不知道它们是什么,或者哪种是最好的或足够好。

答案1

在bash中

while read -r word
do
    grep -q "$word" file.before
    if [ $? -ne "0" ]
    then
        echo "$word not in file"
     fi
done < <(cut -f1 -d" " file.after)

to -qgrep 告诉它保持安静,然后您可以询问是否$?有匹配。01

答案2

你会想做更多类似这样的事情:

for i in $(cat /tmp/10218.after)
do
    grep $(echo ${i} | cut -f1) /tmp/10218.before
done

如果你想要更花哨一点,并在 grep 失败时输出一些内容,你可以这样做:

for i in $(cat /tmp/10218.after)
do
    COUNT=grep -c $(echo ${i} | cut -f1) /tmp/10218.before
    if [[ ${COUNT} -eq 0 ]]
    then
        echo "${i}: Not Found"
    else
        echo "${i}: Found"
    fi
done

答案3

使用perl。

#!/usr/bin/perl

use strict;
use warnings;

my %words_to_find;

open ( my $input, "<", "/tmp/10218.after" );
while ( my $line = <$input> )
{
  my ( $word ) = ( $line =~ m/\A(\S+)\s/ );
  $words_to_find{$word}++;
}
close ( $input );

open ( my $search, "<", "/tmp/10218.before" ); 
while ( my $line = <$search> )
{
  foreach my $word ( key %words_to_find )
  { 
    if ( $line =~ m/$word/ )
    {
      print $line;
      last;
    }
  }
}
close ( $search );

像这样的事情应该可以解决问题。

答案4

您的代码似乎正在做的是提取一个文件中制表符分隔列表中的第一个字段,然后尝试在第二个文件中查找这些单词。

您可以通过不将单词列表存储在数组中来稍微简化这一点:

cut -f1 /tmp/10218.after | grep -f /dev/stdin /tmp/10218.before

这将从第一个文件中提取单词,然后将它们直接传递给grep用于匹配第二个文件的模式。

不过,我们可以在这里做一些优化。首先,我们可以确保单词列表仅包含独特的字:

cut -f1 /tmp/10218.after | sort -u | grep -f /dev/stdin /tmp/10218.before

grep其次,我们可以确保字符串比较而不是正则表达式匹配:

cut -f1 /tmp/10218.after | sort -u | grep -F -f /dev/stdin /tmp/10218.before

然后,我们可能不想grep返回子字符串的匹配项(例如beein bumblebee):

cut -f1 /tmp/10218.after | sort -u | grep -wF -f /dev/stdin /tmp/10218.before

我们还可以确保只匹配中的单词第一的通过将单词重写为锚定正则表达式(和 drop -F)来删除第二个文件的列:

cut -f1 /tmp/10218.after | sort -u | sed 's/^/^/' | grep -w -f /dev/stdin /tmp/10218.before

sed命令只是^在每行的开头插入,这样bee我们就得到了正则表达式,而不是字符串^bee


或者,我们可以只使用一个awk程序来为我们完成所有事情:

awk -F '\t' 'FNR == NR { words[$1]++; next } words[$1]' /tmp/10218.after /tmp/10218.before

这会将第一个文件的第一个制表符分隔列作为键读取到数组中words,然后根据这些键检查第二个文件中的单词。如果第二个文件中的单词作为键出现,则打印第二个文件中的行。


如果您不关心输出的顺序,您也可以使用join

join <( cut -f1 /tmp/10218.after | sort -u -b ) <( sort -b /tmp/10218.before )

bash这种编写命令的特殊方式需要一个了解进程替换的shell(例如) <(...)

在其他外壳中:

cut -f1 /tmp/10218.after | sort -u -b -o keys
sort -b -o data /tmp/10218.before
join keys data

相关内容