我有一个程序,它在标准输出上写入一个字符串值列表,每行一个,我想实时显示不同值的列表以及每个值出现的次数。
例如,从此输出:
apple
carrot
pear
carrot
apple
我需要一个生成此输出的命令(最好实时更新):
apple: 2
carrot: 2
pear: 1
任何想法?
答案1
为了扩展 @Bratchley 在评论中所说的内容,如果您将程序的输出打印到文件中,那么您可以在终端中运行 then命令,通过包含如下标志watch
来获得近乎实时的输出视图:-n
watch -n 0.1 "cat yourprograms.log | sort | uniq -c | sort -rn"
注意:“-n”标志设置刷新间隔。 “watch”的最短时间是 0.1 秒(或 1/10 秒),而且不能更短。
示例输出:
Every 0.1s: cat yourprograms.log | sort | uniq -c | sort -rn
6 things
4 mine
3 dot
1 below
包含| sort -rn
允许更好的排序视图。按相反的数字顺序sort -rn
对 的输出进行排序。uniq -c
如果您只关心前 10 个,则可以包含head
如下命令:
watch -n 0.1 "cat yourprograms.log | sort | uniq -c | sort -rn | head"
答案2
这是一个可以完成您想要的功能的小型 Python 2 程序。这些单词按首次出现的时间顺序列出,即每个新单词都添加到列表的底部,但按字母顺序或按出现次数的顺序对单词进行排序会很容易。
输出可能会更整洁一些,例如,如果您知道最大字符串长度,则出现次数可以在一列中对齐。
字数统计.py
#! /usr/bin/env python
''' Real-time word counting
Written by PM 2Ring 2015.01.29
From http://unix.stackexchange.com/q/181722/88378
'''
CSI = '\x1b['
clear = CSI + '2J' + CSI + 'H'
def main():
words = []
wordcount = {}
while True:
try:
word = raw_input()
except (KeyboardInterrupt, EOFError):
print
break
if word not in wordcount:
words.append(word)
wordcount[word] = 1
else:
wordcount[word] += 1
print clear
for word in words:
print '%s: %d' % (word, wordcount[word])
if __name__ == '__main__':
main()
要将 的输出通过管道传输yourprog
到该程序中,您可以执行以下操作:
yourprog | python wordcount.py
假设它wordcount.py
在当前目录中。
或者,授予wordcount.py
执行权限(例如chmod a+x wordcount.py
)并将其放入命令 PATH 列表中的目录(即执行时列出的目录echo "$PATH"
)。然后你可以做
yourprog | wordcount.py
你可以在任何地方运行它。
如果您只有 Python 3 而没有 Python 2,则该程序将需要一些小的更改才能运行。
FWIW,这是我为测试上述代码而编写的另一个 Python 脚本。它每 0.5 秒打印一个随机单词,每行一个单词。
随机词.py
#! /usr/bin/env python
import random, time
wordlist = [
'apple',
'carrot',
'pear',
'orange',
'banana',
'cabbage',
'potato'
]
def main():
#Time delay between words, in seconds
delay = 0.5
while True:
try:
print random.choice(wordlist)
time.sleep(delay)
except KeyboardInterrupt:
print
break
if __name__ == '__main__':
main()
您可以运行它,将其输出通过管道传输到wordcount.py
如下所示:
python -u randwords.py | python wordcount.py
该-u
标志告诉 Python 解释器使用无缓冲 I/O。
答案3
简单的 awk 事情。使用一些 ANSI 序列进行移动和清除...
#!/usr/bin/awk -f
BEGIN {
print "Stats:\n---------------------------------"
}
function clear() {
for (k in ar)
printf "\r\033[K\033[1A"
}
function stats() {
for (k in ar)
printf "%-10s: %d\n", k, ar[k]
}
/./{
clear()
if (!ar[$0])
ar[$0]=1
else
++ar[$0]
stats()
}
示例输出生成器:
#!/bin/bash
declare -a fr=(
apple
carrot
pear
)
range=${#fr[@]}
while ((1)); do
((x = RANDOM % range))
printf "%s\n" "${fr[$x]}"
sleep .5
done
运行为:
$ ./fruit_script | ./awk_script
扩展颜色、隐藏光标等:
#!/bin/bash
quit()
{
printf "\r\033[K\033[?25h"
}
trap quit SIGINT
awk '
BEGIN {
width=3
printf "\033[?25l"
print "Stats: (Ctrl-c to quit)\n---------------------------------"
}
function clear() {
for (k in ar)
printf "\r\033[K\033[1A"
}
function stats() {
for (k in ar)
printf "\033[0;34m%-*s\033[0m: \033[1;31m%d\033[0m\n", width, k, ar[k]
}
/./{
if (length($0) + 1 > width)
width=length($0) + 1
clear()
if (!ar[$0])
ar[$0]=1
else
++ar[$0]
stats()
}
'