我有一个这种格式的文本文件:
((abcd@04548_5957:0.0363,(((efgh@00512_777:0.019251010,((igkl@03175_4509:0.01768455)100:((efgh@0.05985636)57:
如何在@
标记之前仅提取4个字符,如果字符串在文件中重复,还要提供数字?像
abcd 1
efgh 2
igkl 1
答案 0 :(得分:4)
(
通过将RS设置为@
,将FS设置为(
,awk会将@
和count
之间的文本作为每条记录的第一个字段。如果该字段的长度为4,则我们在数组{{1}}中递增一个计数器。最后,我们只打印出所有计数。
答案 1 :(得分:3)
假设:
@
之前的任意4个字符构成匹配。使用 GNU grep
:
grep -Po '.{4}(?=@)' file | sort | uniq -c | awk '{ print $2, $1 }'
-o
指示grep
仅输出每行的匹配部分。
GNU grep
' -P
选项支持PCREs,支持环视断言(以及其他功能);在这种情况下,他们允许使用积极的预见断言(?=@)
来检测 @
,而不将其包括在匹配中。
uniq -c
获取sort
ed输入,并将具有相同内容的相邻行折叠到一行前面,并以空格分隔。
awk '{ print $2, $1 }'
只需交换两个输出列,即可在计数前放置匹配项。
(在(
和@
之间匹配的更强大的替代方案:
grep -Po '\(+\K.*?(?=@)' file | sort | uniq -c | awk '{ print $2, $1 }'
)
使用 BSD / macOS grep
:
grep -Eo '.{4}@' file | sort | uniq -c | awk '{ print substr($2, 1, length($2)-1), $1 }'
[只需要 BSD / macOS grep
]概念上稍微简单的变体(尽管效率稍低),如glenn jackman所示:
grep -Eo '.{4}@' file | tr -d @ | sort | uniq -c | awk '{ print $2, $1 }'
grep -Eo '.{4}@' file | sed 's/@$//' | sort | uniq -c | awk '{ print $2, $1 }'
答案 2 :(得分:1)
另一个awk
$ awk -F@ '{for(i=1;i<NF;i++) a[substr($i,length($i)-3)]++}
END {for(k in a) print k, a[k]}' file
abcd 1
igkl 1
efgh 2