我有我想要的剪切命令,它可以抓取文件每一行中的第一个单词。然后我想将 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 -q
grep 告诉它保持安静,然后您可以询问是否$?
有匹配。0
1
答案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
返回子字符串的匹配项(例如bee
in 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