提问人:Jason 提问时间:11/13/2023 最后编辑:Jason 更新时间:11/15/2023 访问量:151
计算文本文件中模式的所有唯一实例
Count all unique instances of a pattern in text file
问:
我有一个文件,里面有几行文本,所有文本都以六个十六进制数字、一个空格和一些文本开头。有时,此剩余文本以字符 或 开头,后跟 4 位数字和冒号。例:X
Y
72a0bf Lorem ipsum dolor sit amet, consectetur adipiscing elit.
703e80 X-2310: Duis nibh sem, sollicitudin vel nulla eu, facilisis pulvinar purus.
21b6ac Nam ornare blandit consequat. Vivamus tincidunt eros consequat, egestas
8961cb Y-0110: dui at, lobortis nibh. Sed sed felis vel felis euismod dapibus in vel erat.
ce5dfe X-2310: Curabitur facilisis felis nec ante euismod ultricies at eget turpis. Duis
fa5e8b ac dui ut elit volutpat accumsan quis quis justo. Donec luctus suscipit sem,
我的目标是找到这些和字符串的所有唯一实例。现在,如果我的所有记录都是上述形式,则可以通过例如一些 和其他工具来实现:X***
Y***
grep
awk
bash
$ cat file.txt | grep -E '^[a-z|0-9]{6}[[:space:]](X|Y)-[0-9]{4}' | awk '{print substr($2, 1, length($2) -1)}' | sort | uniq
X-2310
Y-0110
问题在于,在一些包含我正在 ping 的模式的记录中(并且仅在这些记录中),不幸的是,我在剩余文本中有一些这些和字符串的实例,这些实例可以是 1、2、3,...无论数字如何:grep
X***
Y***
c8edc6 X-0101: at tempor tellus commodo sit amet. X-2489 Nunc id gravida est, in rhoncus metus.
fa5e8b Y-9410: ac X-1320 X-0101 dui ut elit Y-9416 volutpat accumsan X-0101 quis X-2000 quis justo.
e29ac0 Y-5751: Vivamus Y-0110 vehicula Y-2021 dolor X-0101 a pretium.
这在上面的脚本中引起了麻烦,因为我只在寻找行首附近的模式。我希望能够找到字符串和 .有什么想法吗?唯一的限制是,由于环境限制,它必须是一个解决方案。X***
Y***
bash
答:
1赞
Jason
11/13/2023
#1
$ grep -E --only-matching '(X|Y)-[0-9]{4}' file.txt | sort | uniq
做诀窍。
评论
0赞
Ed Morton
11/14/2023
这将不理想地匹配以下任何一项:( 不以 ) 结尾 ,或 (第二个字段与 ) 不完全匹配,或 ( 不是第二个字段)。foo X-1111 bar
X-1111
:
foo X-1111:2222 bar
^[XY]-[0-9]{4}:$
foo bar this X-1111: that
X-1111:
2赞
Sash Sinha
11/13/2023
#2
请尝试以下命令:
$ grep -oE '(X|Y)-[0-9]{4}' file.txt | sort -u
X-2310
Y-0110
解释:
-o
仅输出线路的匹配部分。-E
用于扩展正则表达式。(X|Y)-[0-9]{4}
匹配以四位数字开头或后跟四位数字的任何字符串的正则表达式。X-
Y-
sort -u
:这将对匹配项进行排序并过滤掉重复项,保留唯一项目。
评论
0赞
Ed Morton
11/14/2023
这将不理想地匹配以下任何一项:( 不以 ) 结尾 ,或 (第二个字段与 ) 不完全匹配,或 ( 不是第二个字段)。foo X-1111 bar
X-1111
:
foo X-1111:2222 bar
^[XY]-[0-9]{4}:$
foo bar this X-1111: that
X-1111:
0赞
Sash Sinha
11/14/2023
@EdMorton 添加一个否定的前瞻性断言,即前面的模式后面没有紧跟冒号,即 ?这对你的例子有用吗?(?<!:)
(X|Y)-[0-9]{4}
:
grep -oE '(X|Y)-[0-9]{4}(?<!:)' file.txt | sort -u
0赞
Ed Morton
11/14/2023
BRE(默认由 sed 和 grep 使用)和 ERE(默认由 awk 使用,sed 和 grep 使用 )都不支持任何类型的环视。你必须使用 GNU grep 支持的 PCRE 来查看,但那时你最好使用,因为除了匹配正则表达式之外,你还需要做更多的事情(限制它在一个字段上匹配并只输出该字段的一部分)。-E
-P
perl
2赞
markp-fuso
11/13/2023
#3
一个想法:awk
awk '$2 ~ /^[XY]-[0-9]{4}:$/ && !seen[$2]++ { print substr($2,1,6) }' file.txt
哪里:
- 如果第二个字段的格式为 和 ...
[XY]-####:
- 我们以前从未见过第二个字段(第二个字段用作数组的索引;我们第一次遇到这个测试,所以计算为“真”;连续的匹配有,所以是假的)
seen[$2] == 0
!0
seen[$2] > 0
!(1+)
- 剥离结肠
print/substr()
这将生成:
X-2310
Y-0110
注意:这会在处理记录时生成输出;如果需要保证输出的顺序,则通过管道传递给sort
0赞
Mohommad Belal
11/13/2023
#4
根据这个问题,我所理解的是:
从给定文件中找到所有以“X-”或“Y-”开头的唯一字符串,后跟 4 位数字。
我希望这能有所帮助:
grep -oE '\b[XY]-[0-9]{4}\b' file.txt | sort | uniq
解释:
格雷普
- -o 或 --only-matching :P rint 仅匹配行的匹配非空部分,使用
- -E 或 --extended-regexp :将模式解释为扩展正则表达式 (ERE)
正则表达式:
- \b...\b :d消除文本的边界。
- [XY] :X 或 Y 字符
- '-':字符连字符“-”
- [0-9]{4} : 任意长度的数字 4.
财政年度:
评论
0赞
Ed Morton
11/14/2023
这将不理想地匹配(不以 ) 结尾,并且不理想地匹配(不是第二个字段)。foo X-1111 bar
X-1111
:
foo bar this X-1111: that
X-1111:
0赞
Diego Torres Milano
11/13/2023
#5
类似的想法,使用 as 分隔符awk
:
awk -F '[ :]' '$2 ~ /[XY].*/&&!a[$2]++ {print $2}'
评论
0赞
Ed Morton
11/14/2023
这将不受欢迎地匹配(不以 )。foo X-1111 bar
X-1111
:
0赞
ufopilot
11/13/2023
#6
$ awk 'match($2,/^[XY]-[0-9]{4}:$/) && !seen[$2]++ && sub(/:$/,"",$2) && $0=$2' file
X-0101
Y-9410
Y-5751
X-2310
Y-0110
0赞
RavinderSingh13
11/13/2023
#7
使用您展示的示例和尝试,请尝试以下,从 Mark 的回答中汲取灵感。简单的解释是:
- 检查条件,如果第 2 个字段等于
^[XY]-[0-9]{4}:$
- 并确保数组之前没有任何当前值 $2,然后打印当前行的 $2。
seen
awk '
$2 ~ /^[XY]-[0-9]{4}:$/ && !seen[$2]++{
sub(/:$/,"",$2)
print $2
}
' Input_file
2赞
Ed Morton
11/14/2023
#8
我通常会去这个或其他任何涉及字段匹配的东西,但只是为了完整性:使用 GNU for 和 plus :awk
sed
-E
\s/\S
sort
$ sed -En 's/^\S+\s+([XY]-[0-9]{4}):(\s.*)?$/\1/p' file | sort -u
X-2310
Y-0110
0赞
Andrej Podzimek
11/15/2023
#9
在没有外部程序的 Bash 中:
declare -Ai matches=();
while IFS= read -r line; do
read -ra tokens <<< "$line"
for token in "${tokens[@]:1}"; do
[[ "$token" = [XY]-[0-9][0-9][0-9][0-9] ]] && ((++matches["$token"]))
done
done < /path/to/input.txt
printf '%s\n' "${!matches[@]}"
评论
grep -o
sort -u
grep
72a0bf Lorem ipsum X-9999: dolor
grep
grep
awk
bash
bash