28
這個應該是在sh輸出pipe給head 在處理速度上的問題
以netman大的例子,會有個問題是在於 echo n:$n >&2 這時echo是redirect
1
2
3
4
5
6
7
8
9
10
n:10
以strace來看系統的動作
strace -s 128 ./1.sh 可看到並非連輸出到stdout , <--- 所以有可能head認為1~10時己經結束 , n:10就要看來不來得及被head接到 , 如果n:10導向的速度快,就有可能插入到head的輸出中,所以實際上head接了二次輸入, 因此head輸出了第一和第二個輸入才會在不特定行數中輸出
如果第二個輸入前head就結束程序, n:10就lost掉了
read(255, "#!/bin/bash\nLANG=C\nn=0\n#echo \"---$n\"\nfor ((i=1;i<=10;i++)); do\n\techo $i\n\t((n++))\ndone\necho n:$n >&2\n", 100) = 100
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 18), ...}) = 0
write(1, "1\n", 21
) = 2
write(1, "2\n", 22
) = 2
write(1, "3\n", 23
) = 2
write(1, "4\n", 24
) = 2
write(1, "5\n", 25
) = 2
write(1, "6\n", 26
) = 2
write(1, "7\n", 27
) = 2
write(1, "8\n", 28
) = 2
write(1, "9\n", 29
) = 2
write(1, "10\n", 310
) = 3
fcntl(1, F_GETFD) = 0
fcntl(1, F_DUPFD, 10) = 10
fcntl(1, F_GETFD) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0 <---
dup2(2, 1) = 1 <---
fcntl(2, F_GETFD) = 0 <---
write(1, "n:10\n", 5n:10 <---
) = 5
dup2(10, 1) = 1
fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(10) = 0
read(255, "", 100) = 0
如果把最後的>&2拿掉就會連續輸出 , head得到的結果就會準確
read(255, "#!/bin/bash\nLANG=C\nn=0\n#echo \"---$n\"\nfor ((i=1;i<=10;i++)); do\n\techo $i\n\t((n++))\ndone\necho n:$n\n", 96) = 96
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 18), ...}) = 0
write(1, "1\n", 21
) = 2
write(1, "2\n", 22
) = 2
write(1, "3\n", 23
) = 2
write(1, "4\n", 24
) = 2
write(1, "5\n", 25
) = 2
write(1, "6\n", 26
) = 2
write(1, "7\n", 27
) = 2
write(1, "8\n", 28
) = 2
write(1, "9\n", 29
) = 2
write(1, "10\n", 310
) = 3
write(1, "n:10\n", 5n:10
) = 5
read(255, "", 96)
如何證明head在不同階段結束呢? 簡單加個sleep 3在n:10之前是最明顯的了, head有機會還沒等到sleep 3就先結束整個程序了
也可以把n:10改成第二個for輸出也很明顯 , 執行./a1.sh |strace head 也只會看到第一個for的write 輸出動作 ,所以能研判第二個輸出己不在strace head裡的的程序上了,可能head跑了第二支function接輸入
所以在不同cpu和系統速度也是會有些微差距, 應該說是bash pipe redirect緩慢還是head tail結束太快 , 可能沒有一個標準答案
因為bash本來就不保證結果的順序性, 除非bash開始提供類似交握或protocol.... 以上只是個初步簡易的測試,有錯誤的話還請提點