我正在寻找一种在文件中搜索多行模式的方法。
例如,假设这个数字列表是我的输入文件:
3
2
5
4
8
2
5
4
2
4
2
5
4
如果我想搜索第 2-4 行(含)的实例,我希望结果为:
3
因为这是那些特定行被精确重复的次数。我还希望它能够处理文件中任何给定数量的行以及任何给定的行号范围。
答案1
你可以使用pcregrep,在大多数发行版中都可用。以下命令匹配固定字符串。
pcregrep -Mc '^2\n5\n4$' input.txt
解释
从手册页来看,pcregrep 是“具有与 Perl 兼容的正则表达式的 grep”。
-M
:匹配多行正则表达式-c
:输出匹配的数量(count),而不是匹配本身^2\n5\n4$
:2、5、4 的正则表达式,每个在单独的行上。
取而代之的是特定线条的图案
问题中的后续评论表明要匹配的模式不是固定字符串,而是一般的“第 2 行到第 4 行”。在这里,您可以使用命令替换来解析输入文件中的行。
pcregrep -Mc "^\Q$(sed -n 2,4p input.txt)\E$" input.txt
解释
tail -n+2 input.txt
:输出文件,从第 2 行开始head -n3
: 只输出前三行\Q...\E
:引用基本字符串匹配而不是正则表达式匹配的部分...
(假设命令的输出不包含\E
)。
请注意,它假设 输出的最后几行sed ... input.txt
不为空,因为命令替换 ( $(...)
) 条带全部尾随换行符。
答案2
$ perl -l -0777pe '$_=()=/^2\n5\n4$/mg' input_file
3
在职的:
-0777
=> slurp模式,意味着读入整个文件。-p
=> 在读取下一条记录之前,将当前记录打印到$_
标准输出。-l
=> 设置RS = ORS =“\n”- 正则
/^2\n5\n4$/mg
表达式隐式应用于$_
,在我们的例子中是整个文件。除了字符串开头和字符串结尾之外,正则表达式修饰符/m
还应匹配行结尾和开头。修饰符将获取整个文件/g
中的所有匹配项。$_
- 我们在列表上下文中执行此操作,并将其分配给一个空列表。 $_ 因此被重新分配列表中的元素数量,这是正则表达式真正匹配的次数。
华泰
答案3
您的帖子没有提到任何正则表达式支持的要求,因此我假设您将搜索固定的文字文本字符串。
这可能不是您见过的最快的算法,但如果您有足够的时间,它是有效的。它有一个小缺陷,如果有多个 N 行模式以相同的第一行开头并且具有相同的 SHA256 哈希值,则会给出错误的结果。它假设所有可能的 N 行模式都具有唯一的 SHA256 哈希值。
对于大文件,尤其是那些包含大量出现的模式第一行的文件,它会非常慢。
#!/usr/bin/env bash
# What's the name of the list file?
LIST=list
# What's the name of the pattern file?
PATTERN=pattern
# We'll figure out how many times the pattern lines appear (consecutively) in the list.
# Where's your SHA256 tool?
SHA256=/sbin/sha256
# what's the first line of pattern?
PATTERN_START="$(head -1 $PATTERN)"
# where in the list does that single line appear (what line numbers?)
START_LINES="$(grep -nx "$PATTERN_START" $LIST | sed -e 's/:.*//')"
# how many lines long is the pattern?
PAT_LEN="$(grep -c ^ < $PATTERN)"
echo Pattern is $PAT_LEN lines long, and might start at any of these lines:
echo $START_LINES
PAT_HASH="$($SHA256 < "$PATTERN")"
# So how many times does $PATTERN appear consecutively in $LIST?
PAT_COUNT=0
for LINE in $START_LINES
do
HASH="$(tail +$LINE $LIST | head -$PAT_LEN | $SHA256 -q)"
if [ "$HASH" = "$PAT_HASH" ]
then
echo match at line $LINE
PAT_COUNT=$(($PAT_COUNT+1))
fi
done
echo The pattern was found $PAT_COUNT times
输出:
$ cat list
3
2
5
4
8
2
5
4
2
4
2
5
4
$ cat pattern
2
5
4
$ . foo.sh
Pattern is 3 lines long, and might start at any of these lines:
2 6 9 11
match at line 2
match at line 6
match at line 11
The pattern was found 3 times
答案4
怎么样
a="2 5 4"; tr '\n' ' ' < test | grep -o "[^0-9]$a[^0-9]" | wc -l
使用您选择的分隔符......
22 5 44
您需要正则表达式来防止在......或类似情况下发生匹配