Bash 只计算输出的前X行的最快方法
我有一个来自Bash 只计算输出的前X行的最快方法,bash,wc,Bash,Wc,我有一个来自tshark过滤器的大型终端输出,我想检查行数(本例中的包数)是否达到X的阈值 这个操作是在许多大文件的循环中完成的,所以我想在这里最大限度地提高性能 我想知道的是,wc-l是计算终端命令输出的最快方法 我的行如下所示:(所以tshark命令在这里并不重要,所以为了可读性,我替换了它) 虽然这几乎可以正常工作,但我想知道是否有办法在阈值之后停止。只要达到(或未达到)阈值,准确的数字就无关紧要 一个猜测是: HEAD=$((THRESHOLD+1)) [[ $(tshark -r $f
tshark
过滤器的大型终端输出,我想检查行数(本例中的包数)是否达到X的阈值
这个操作是在许多大文件的循环中完成的,所以我想在这里最大限度地提高性能
我想知道的是,wc-l
是计算终端命令输出的最快方法
我的行如下所示:(所以tshark命令在这里并不重要,所以为了可读性,我替换了它)
虽然这几乎可以正常工作,但我想知道是否有办法在阈值之后停止。只要达到(或未达到)阈值,准确的数字就无关紧要
一个猜测是:
HEAD=$((THRESHOLD+1))
[[ $(tshark -r $file -Y "tcp.stream==${streamID}" | head -n $HEAD | wc -l) -gt $THRESHOLD ]] || echo "not enough"
但是,通过管道连接到其他服务并增加阈值可能会更慢,不是吗
编辑:将示例代码更改为工作的tshark片段使用包装器启动
tshark
(或tail-f-n+1文件
),该包装器检查输出行计数并在阈值后退出。下面是一个在awk中使用seq
模拟tshark
的示例:
$ awk '
BEGIN {
cmd="seq 1 100" # command to execute, outputs 100 lines
while((cmd|getline res)>0 && ++c<50); # count to 50 lines and exit
print res # test to show last line of input
exit
}'
seq
在50岁之后继续运行一段时间,但最终退出。更改cmd=“seq 1 10000000 | tee foo”
和tail foo
我得到:
...
11407
11408
11
基准
只有一种方法可以找到答案:自己进行基准测试。
下面是我想到的一些实现
gen() { seq "$max"; }
# functions returning 0 (success) iff `gen` prints less than `$thold` lines
a() { [ "$(gen | head -n"$thold" | wc -l)" != "$thold" ]; }
b() { [ -z "$(gen | tail -n+"$thold" | head -c1)" ]; }
c() { [ "$(gen | grep -cm"$thold" ^)" != "$thold" ]; }
d() { [ "$(gen | grep -Fcm"$thold" '')" != "$thold" ]; }
e() { gen | awk "NR >= $thold{exit 1}"; }
f() { gen | awk -F^ "NR >= $thold{exit 1}"; }
g() { gen | sed -n "$thold"q1; }
h() { mapfile -n1 -s"$thold" < <(gen); [ -z "$MAPFILE" ]; }
max=1''000''000''000
for fn in {a..h}; do
printf '%s: ' "$fn"
for ((thold=1''000''000; thold<=max; thold*=10)); do
printf '%.0e=%2.1fs, ' "$thold" "$({ time -p "$fn"; } 2>&1 | grep -Eom1 '[0-9.]+')"
done
echo
done
结果
以下是我的系统上的结果:
a: 1e+06=0.0s, 1e+07=0.1s, 1e+08=0.8s, 1e+09=8.9s,
b: 1e+06=0.0s, 1e+07=0.1s, 1e+08=0.9s, 1e+09=8.4s,
c: 1e+06=0.0s, 1e+07=0.2s, 1e+08=1.6s, 1e+09=16.1s,
d: 1e+06=0.0s, 1e+07=0.2s, 1e+08=1.6s, 1e+09=15.7s,
e: 1e+06=0.1s, 1e+07=0.8s, 1e+08=8.2s, 1e+09=83.2s,
f: 1e+06=0.1s, 1e+07=0.8s, 1e+08=8.2s, 1e+09=84.6s,
g: 1e+06=0.0s, 1e+07=0.3s, 1e+08=3.0s, 1e+09=31.6s,
h: 1e+06=7.7s, 1e+07=90.0s, ... (manually aborted)
b:。。。1e+08=0.9s…
意味着接近b
花费了0.9秒来发现seq 100000000
的输出至少有1e+08
(=100000)行
结论
从这个答案中给出的方法来看,b
显然是最快的。但是,实际结果可能因系统而异(对于head
,grep
,…)和您的atual用例,有不同的实现和版本。我建议使用实际数据进行基准测试(即,将gen()
中的seq
替换为t共享输出行
,并将thold
设置为任何实际使用的值)
如果您需要更快的方法,您可以使用
stdbuf
和LC_ALL=C
进行更多的实验,您是否确实尝试过计时?我想我无法模拟你的平台你的想法是正确的。避免产生额外的进程。你的问题是小鸡或鸡蛋的问题。在进行有效比较之前,您必须至少阅读$THRESHOLD
行(或EOF
)。由于您是管道t共享输出
,因此该过程将在传递到wc
或head
之前完成。除非$THRESHOLD
和文件大小之间有几十万行+差异,否则我不知道您在wc
或head
之间节省了任何时间。你只需要对最坏的情况进行计时就可以了。在我的场景中,很难隔离这一步(需要更多的编码),所以我的想法是在开始工作之前先考虑一下,最终什么都不做。感谢David的回答……您可以将tsharks
的输出通过管道传输到一个程序中,该程序不仅可以验证它(如您所述),还可以关闭它的stdin。写入程序(tsharks
)应该在管道破裂的情况下中止。@user1934428head
已经关闭stdin。令人惊讶的是b
对我来说也是最快的。@KamilCuk感谢您分享您的结果。你为什么会感到惊讶?我想我希望只有一个进程,比如awk
获胜,而不是两个进程tail | head
。在我的系统上,这也是方法b)。感谢这个很好的基准测试示例!我本以为sed会在这里获胜<代码>头部和尾部确实很快。。。但没那么快。我相信样本数据也是一个玩家。如果您将gen
替换为printf--“x%.0s”$(seq$(max*70))| fold-w70
和printf--“x%.0s”$(seq$(max*6000))| fold-w6000
(后者被选择为大于PIPE\BUF
gen() { seq "$max"; }
# functions returning 0 (success) iff `gen` prints less than `$thold` lines
a() { [ "$(gen | head -n"$thold" | wc -l)" != "$thold" ]; }
b() { [ -z "$(gen | tail -n+"$thold" | head -c1)" ]; }
c() { [ "$(gen | grep -cm"$thold" ^)" != "$thold" ]; }
d() { [ "$(gen | grep -Fcm"$thold" '')" != "$thold" ]; }
e() { gen | awk "NR >= $thold{exit 1}"; }
f() { gen | awk -F^ "NR >= $thold{exit 1}"; }
g() { gen | sed -n "$thold"q1; }
h() { mapfile -n1 -s"$thold" < <(gen); [ -z "$MAPFILE" ]; }
max=1''000''000''000
for fn in {a..h}; do
printf '%s: ' "$fn"
for ((thold=1''000''000; thold<=max; thold*=10)); do
printf '%.0e=%2.1fs, ' "$thold" "$({ time -p "$fn"; } 2>&1 | grep -Eom1 '[0-9.]+')"
done
echo
done
a && echo "tsharks printed less than $thold lines"
a: 1e+06=0.0s, 1e+07=0.1s, 1e+08=0.8s, 1e+09=8.9s,
b: 1e+06=0.0s, 1e+07=0.1s, 1e+08=0.9s, 1e+09=8.4s,
c: 1e+06=0.0s, 1e+07=0.2s, 1e+08=1.6s, 1e+09=16.1s,
d: 1e+06=0.0s, 1e+07=0.2s, 1e+08=1.6s, 1e+09=15.7s,
e: 1e+06=0.1s, 1e+07=0.8s, 1e+08=8.2s, 1e+09=83.2s,
f: 1e+06=0.1s, 1e+07=0.8s, 1e+08=8.2s, 1e+09=84.6s,
g: 1e+06=0.0s, 1e+07=0.3s, 1e+08=3.0s, 1e+09=31.6s,
h: 1e+06=7.7s, 1e+07=90.0s, ... (manually aborted)