我想知道“ABCD”(文件 A)在数据库(文件 B)中出现了多少次。同样,我想知道文件 A 中针对数据库出现的每一行。我需要一个可以简化我工作的自动化命令,因为我在文件 A 中有大量数据,我想在多个数据库中搜索这些数据。我只是将字符加粗以便于理解。
文件A
ABCD
EFG
HIJKL
MNO
PQRSTU
文件 B
XYZA B C DFORNTUFPSRWSABCFYWSZCFTHBFORTYBJNFA B C D德纤维增强混凝土交流电压恢复时间纤维增强混凝土韋姆諾普查纤维增强混凝土韓國
期望输出:
ABCD 2
EFG 3
HIJKL 4567
MNO 0
PQRSTU 7652
答案1
我的建议是:
IFS=; while read -r word; do printf "%s " $word; grep -o $word b | wc -l; done < a
- 使用
while
我们循环到单词(文件 a) printf "%s " $word
:打印单词名称,例如:ABCDgrep -o $word b | wc -l
:计数并打印发生次数
答案2
Python
count_patterns.py
脚本。对于大文件来说应该相当好用。用于OrderedDict
记录命令行上提供的文件 A 中的所有模式,并在文件 B 中搜索它们。
#!/usr/bin/env python3
import sys
from collections import OrderedDict
with open(sys.argv[1]) as pattern_file, open(sys.argv[2]) as data_file:
patterns = OrderedDict.fromkeys(map(str.strip, pattern_file), 0)
for line in data_file:
for p in patterns:
patterns[p] += line.count(p)
for kv in patterns.items():
print(*kv)
用法:
$ ./count_patterns.py file_A.txt file_B.txt
ABCD 4
EFG 3
HIJKL 0
MNO 1
PQRSTU 0
重击方法。
这使用了进程替换sed
,让我们将文件 A 拆分为换行符**
,并用它grep -c
来计算匹配的行数。
$ cat file_B.txt
ABCD**FORNTUFPSRWSABCFYWSZCFTHBFORTYBJNF**ABCD**D**EFG**ACVRT**EFG**PQRMNOOPQ**EFG**ZXXXYY
ABCD**FORNTUFPSRWSABCFYWSZCFTHBFORTYBJNF**ABCD
$ cat file_A.txt
ABCD
EFG
HIJKL
MNO
PQRSTU
$ while IFS= read -r pattern; do printf "%s\t" "$pattern"; grep -c "$pattern" < <( sed 's/\*\*/\n/g' file_B.txt ); done < file_A.txt
ABCD 4
EFG 3
HIJKL 0
MNO 1
PQRSTU 0
这不是最好的方法,可能不适合大文件,但可以工作。不建议使用 bash 方法,但如果数据集不大,它可以工作。
答案3
猛击
使用 Bash 的结合数组:
#!/bin/bash
set -eu
declare -A patterns
while IFS= read -r p; do
patterns["$p"]=0
done < "$1"
while IFS='*' read -ra l; do
for r in "${l[@]}"; do
if [ -n "$r" ] && [ -v patterns["$r"] ]; then
patterns[$r]=$((${patterns["$r"]} + 1))
fi
done
done < "$2"
for p in "${!patterns[@]}"; do
printf '%s\t%u\n' "$p" "${patterns["$p"]}"
done
用法:
bash count-patterns.sh pattern-list.txt word-list.txt
Python 3
使用自定义字典类和函数式数据处理:
#!/usr/bin/env python3
import sys, itertools, collections
class MyCounter(collections.UserDict):
def __init__(self, _dict):
self.data = _dict
def update(self, iterable):
for key in iterable:
self.data[key] += 1
with open(sys.argv[1]) as pattern_file:
patterns = MyCounter({ s.rstrip('\n'): 0 for s in pattern_file })
with open(sys.argv[2]) as wordlist_file:
patterns.update(filter(patterns.__contains__,
itertools.chain.from_iterable(map(
lambda s: s.rstrip('\n').split('**'), wordlist_file))))
for p in patterns.items():
print(*p, sep='\t')
用法:
python3 count-patterns.py pattern-list.txt word-list.txt
C++
#include <cstddef>
#include <utility>
#include <unordered_map>
#include <iostream>
#include <fstream>
namespace std
{
template <class Ch, class Tr, class K, class V, class H, class Eq>
basic_ostream<Ch,Tr> &operator<<( basic_ostream<Ch,Tr> &os,
const std::unordered_map<K,V,H,Eq> &m )
{
for (const typename std::unordered_map<K,V,H,Eq>::value_type &i: m)
os << i.first << '\t' << i.second << '\n';
return os.flush();
}
}
template <class Key, class Hash = std::hash<Key>, class Equal = std::equal_to<Key>>
class counter :
public std::unordered_map<Key, std::size_t, Hash, Equal>
{
private:
typedef std::unordered_map<Key, std::size_t, Hash, Equal> _base;
public:
void update_existing( const Key &k, std::size_t count = 1 )
{
const typename _base::iterator match = this->find(k);
if (match != this->end())
match->second += count;
}
};
int main( int argc, char *argv[] )
{
if (argc != 3)
{
std::cerr << "Usage: " << argv[0] << " <PATTERN-FILE> <WORDLIST-FILE>" << std::endl;
return 2;
}
counter<std::string> patterns;
std::string buf;
{
std::ifstream pattern_file(argv[1]);
while (pattern_file.good() && !std::getline(pattern_file, buf).fail())
patterns.emplace(std::move(buf), 0);
}
if (!patterns.empty())
{
std::ifstream wordlist_file(argv[2]);
while (wordlist_file.good() && !std::getline(wordlist_file, buf).fail())
{
static const char delim[] = {'*', '*'};
std::size_t offset = 0, p = 0;
while ((p = buf.find(delim, offset, sizeof(delim))) != std::string::npos)
{
patterns.update_existing(buf.substr(offset, p - offset));
offset = p + sizeof(delim);
}
patterns.update_existing(buf.erase(0, offset));
}
}
std::cout << patterns;
}
编译使用:
c++ -std=c++11 -o count-patterns count-patterns.cpp
用法:
./count-patterns pattern-list.txt word-list.txt
答案4
这是一个awk
可以完成您所期望的事情的程序:
代码:
BEGIN {FS="*"}
FNR==NR {a[$0]=0; next}
{for (i=1; i<=NF; i++) if ($i in a) a[$i]++}
END {
for (i in a) {
print i, a[i]
}
}
如何?
- 将字段 seperaotr 设置为
*
FNR==NR {a[$0]=0; next}
将要匹配的单词加载到数组中a
- 对于每一行,测试并增加 's 之间的字段是否
*
在a
- 打印
a
在END
块中
运行:
awk -f test.awk fileA DB
结果:
ABCD 2
HIJKL 0
EFG 3
MNO 0
PQRSTU 0