shell - 使用嵌套三通不会产生好的结果
问题描述
嵌套三通没有按预期工作,请参阅上面的不同测试:
测试是一个小文件(大约 550 kb):
$ >test
$ for _I in `seq 1 100000`; do
echo "$_I" >> test
done
$ wc -l test
100000 test
这是一些带有嵌套 tee 的代码:
$ cat test.sh
echo "1 :"
cat "$1" |\
tee >(paste -sd+ | bc -l)\
>(wc -l)\
>(sort -k1 -n\
tee >(uniq -c | wc -l)\
>(uniq -c | awk '{ print $1 }' | paste -sd+ | bc -l)\
>(tail -n 1)\
>(head -n 1) &>/dev/null) &>/dev/null
sleep 20
echo "2:"
cat "$1" |\
tee >(paste -sd+ | bc -l)\
>(wc -l)\
>(sort -k1 -n | uniq -c\
tee >(wc -l)\
>(awk '{ print $1 }' | paste -sd+ | bc -l)\
>(sort -k1 -n |\
tee >(tail -n 1)\
>(head -n 1) &>/dev/null) &>/dev/null) &>/dev/null
sleep 20
echo "3:"
cat "$1" |\
tee >(paste -sd+ | bc -l)\
>(wc -l)\
>(sort -k1 -n | uniq -c | wc -l)\
>(sort -k1 -n | uniq -c | awk '{ print $1 }' | paste -sd+ | bc -l)\
>(sort -k1 -n | tail -n 1)\
>(sort -k1 -n | head -n 1) &>/dev/null
sleep 20
这产生了这个结果:
1 :
0
14139
99962730
2:
0
100000
5000050000
3:
1
100000
100000
100000
100000
5000050000
这是一些没有任何 tee 重定向的代码:
$ cat test2.sh
echo "4 :"
echo "sum : `cat $1 | paste -sd+ | bc -l`"
echo "count numbers : `cat $1 | wc -l`"
echo "count uniq : `cat $1 | sort -k1 -n| uniq -c | wc -l`"
echo "uniq sort and sum : `cat $1 | sort -k1 -n | uniq -c | awk '{ print $1 }' | paste -sd+ | bc -l`"
echo "max : `cat $1 | sort -k1 -n | tail -n 1`"
echo "min : `cat $1 | sort -k1 -n | head -n 1`"
以下是供参考的结果:
$ ./test2.sh test
4 :
sum : 5000050000
count numbers : 100000
count uniq : 100000
uniq sort and sum : 100000
max : 100000
min : 1
有人可以解释一下为什么 test.sh 中的案例 1 和 2 不能按预期工作吗?
解决方案
好的:
- 您
|
在第 5 行和第 15 行丢失了。您可能不是有意执行
sort -k1 -n tee <(...) <(...) ...
但sort -k1 -n | tee <(...) <(...) ...
head
实用程序在读取第一行后退出。在它存在之后,它会关闭管道,这使得 tee 退出“过早”。考虑以下:
$ seq 10000 | tee >(head -n1) >(tail -n1) >/dev/null
1
10000 # fine
$ seq 100000 | tee >(head -n1) >(tail -n1) >/dev/null
1
14139 # erroro, this is not ok. tail should have outputted 100000 here. Why doesn't it?
$ seq 100000 | tee >(sponge | head -n1 ) >(tail -n1) >/dev/null
100000 # sponge fixes it
1
$ seq 100000 | tee --output-error=warn >(head -n1) >(tail -n1) >/dev/nul
1
tee: /dev/fd/63: Broken pipe # head exists which closes pipe and that makes tee exit here
10000000
# seq 10000000 | tee -p >(head -n1) >(tail -n1) >/dev/null
1
10000000 # works as expected
的默认值tee
是在写入任何管道时出错时退出。选项在写入管道时忽略错误,并在任何管道退出后继续-p
。tee
以下是使用输出固定的案例 1(缩进不同,但相同):
cat "$1" | tee -p >/dev/null \
>(paste -sd+ | bc -l) \
>(wc -l) \
>(sort -k1 -n | tee -p >/dev/null \
>(uniq -c | wc -l) \
>(uniq -c | awk '{ print $1 }' | paste -sd+ | bc -l) \
>(tail -n 1) \
>(head -n1) \
)
1
100000
100000
100000
100000
5000050000
这是案例 2 固定:
cat "$1" | tee -p >/dev/null \
>(paste -sd+ | bc -l) \
>(wc -l) \
>(sort -k1 -n | uniq -c | tee -p >/dev/null \
>(wc -l) \
>(awk '{ print $1 }' | paste -sd+ | bc -l) \
>(sort -k1 -n | tee -p >/dev/null \
>(tail -n 1) \
>(head -n1)
)
)
1 1
1 99999
100000
100000
100000
5000050000
我想这将是“最快的”(即uniq -c
与案例 1 相比只有一个电话),我想这可能是您对案例 2 的意思:
cat "$1" | tee >/dev/null \
>(paste -sd+ | bc -l) \
>(wc -l) \
>(sort -k1 -n | tee -p >/dev/null \
>(uniq -c | tee -p >/dev/null \
>(wc -l) \
>(awk '{ print $1 }' | paste -sd+ | bc -l) \
) \
>(tail -n 1) \
>(head -n1)
)
它的输出与案例 1 相同。
作为旁注,这些进程替换和tee
命令的输出是不同步的。我的意思是输出的顺序实际上是随机的,并且该行5000050000
到达最后一行是纯粹的运气。
推荐阅读
- sql - 评估所有条件sql
- nuxt.js - Nuxt - 防止直接访问页面目录 url
- windows - 为 firebase serve 命令禁用终端日志
- c# - 如何在 c# Core.net 中将 Byte[] 转换为 Image(jpg, png, etc)
- swiftui - 当前视图后面的视图半透明(像VisualEffectView一样模糊)
- automation - 在特定 LPAR 上使用 ASID 显示和取消多个 stcs
- html - 如何使用 CSS 更改网站的光标?
- angular - 角度路由 - 如何制定路径?
- xpath - 来自财富 500 强的 Google 表格导入功能
- spring-boot - 限速网页客户端