我有一堆巨大的文本文件,每个文件大约100MB。
我想使用grep命令查找包含“INDIANA JONES”的条目:
$ grep -ir 'INDIANA JONES' ./
接下来,我想找到在距离INDIANA JONES
术语的5,000个字符内包含单词PORTUGAL
的条目。我该如何做?
# in pseudocode
grep -ir 'INDIANA JONES' ./ | grep 'PORTUGAL' within 5000 char
grep -ioE ".{5000}INDIANA JONES.{5000}" file.txt | grep "PORTUGAL"
grep
命令中添加-n
标志,并将其管道输送到:cut -f1 -d: > line_numbers.txt
awk
命令来打印这些行:awk 'FNR==NR { a[$0]; next } FNR in a' line_numbers.txt file.txt
awk 'FNR==NR { a[$0]; next } FNR in a' <(grep -ioE ".{50000}INDIANA JONES.{50000}" file.txt | grep -n "PORTUGAL" | cut -f1 -d:) file.txt
对于多个文件,请使用find
和bash
循环:
for i in $(find . -type f); do
awk 'FNR==NR { a[$0]; next } FNR in a' <(grep -ioE ".{50000}INDIANA JONES.{50000}" "$i" | grep -n "PORTUGAL" | cut -f1 -d:) "$i"
done
sudo apt-get install ack-grep
ack-grep是grep的更强大的版本。
在没有完整批处理脚本的情况下,除了使用完整的批处理脚本外,对于您的问题没有简单的解决方案(我能想到的),但是您可以使用- A和-B标志在ack-grep上指定要输出的行数,分别为尾随或引导行。
这可能不是字符数,但是朝着那个方向更进了一步。
虽然这可能不是一个解决方案,但它可能会给您一些如何做到这一点的思路。查找类似于ack、awk、sed等的过滤器,并查看是否可以找到具有此类行为标志的过滤器。
ack-grep手册:
http://manpages.ubuntu.com/manpages/hardy/man1/ack-grep.1p.html
编辑:
我认为令人难过的消息是,你可能认为自己正在寻找的是像这样的东西:
grep "\(INDIANA JONES\).\{1,5000\}PORTUGAL" filename
ack-grep -ira "PORTUGAL" -A 100 -B 100 filename
并且
ack-grep -ira "INDIANA JONES" -A 100 -B 100 filename
用你需要的内容替换100。
您需要获取 ack-grep 返回的匹配项并解析它们,查找其中任何子范围中的匹配项。
在第一个 PORTUGAL ack-grep 匹配项的输出中查找 INDIANA JONES,在第二组匹配项中查找 PORTUGAL。
这可能需要更多的工作,可能涉及到一个 bash 脚本(我可能会尝试在本周内让其工作),但它可以通过将其分解成更易处理的块来解决您的大数据问题。
grep -ir '/INDIANA JONES.{1,5000}PORTUGAL/' ./
? - David542grep
都支持-A
和-B
标志。 - iruvar处理这个问题的一种方法是使用gawk。您可以将记录分隔符设置为INDIANA JONES
或PORTUGAL
,然后对记录执行长度检查(在剥离换行符之后,假设换行符不计入5000的限制)。您可能需要使用find来在目录中递归运行此操作。
awk -v RS='INDIANA JONES|PORTUGAL' '{a = $0;
gsub("\n", "", a)};
((RT ~ /IND/ && prevRT ~/POR/) || (RT ~ /POR/ && prevRT ~/IND/)) && length(a) < 5000{found=1};
{prevRT=RT};
END{if (found) print FILENAME}' file.txt
grep 'INDIANA JONES' . -iR -l | while read filename; do head -c 5000 "$filename" | grep -n PORTUGAL -H --label="$filename" ; done
这段代码的作用如下:
grep 'INDIANA JONES' . -iR -l
。在当前目录及其子目录中搜索所有文件,不区分大小写(-i
),只打印匹配的文件名(-l
),不打印任何内容。| while read filename; do ...|...|...; done
对于每个输入行,将其存储在变量$filename
中并执行管道。现在,对于每个匹配“INDIANA JONES”的文件,我们执行以下操作:
head -c 5000 "$filename"
- 提取前5000个字符grep ...
- 搜索“PORTUGAL”。打印文件名(-H
),但我们使用--label="$filename"
告诉我们要使用的“filename”。同时打印行号-n
。