Echo> dosyası neden echo | sed> dosya?


28

Aşağıdaki örnek beni şaşırttı. Bir bıyık fazlası var aslında kenara ... karşı sezgisel görünüyor kullanıcı zamanı için echo | sedaçılan.

Yalnız çalıştığında neden echobu kadar çok zaman kullanıyor veya soru sed, oyunun durumunu nasıl değiştiriyor? Her iki durumda echoda aynı yankılanmayı yapmanız gerekecek gibi görünüyor ...

time echo -n a\ {1..1000000}\ c$'\n' >file

# real    0m9.481s
# user    0m5.304s
# sys     0m4.172s

time echo -n a\ {1..1000000}\ c$'\n' |sed s/^\ // >file

# real    0m5.955s
# user    0m5.488s
# sys     0m1.580s

1
Bağırsak reaksiyonum tamponlama ile ilgili.
bahamat

1
@ bahamat bence haklısın. Eko, her argüman için ayrı bir write () yapar. Sed onları tamponlar. Bu nedenle, ilk sürümün bir dosya sistemine yazdığı, bir dosya sistemi sürücüsünden blok aygıt katmanına geçen bir milyon yazdığı ve ikinci sürümün bir boruya giren milyonlarca yazdığı ve bir miktar daha az sayıda da daha pahalı çekirdek kod katmanlarından geçen bir yazdığı yazılmıştır.
Alan Curry,

@ bahamat Kesinlikle tamponlama. time echo ... |cat >fileve hatta sürümüne time echo ... |perl -ne 'print'benzer zamanlar sed.
StarNamer

4
İyi açıklamalar için herkese teşekkürler ... Böylece çok satırlı büyük yazılar için (
bash'da

Yanıtlar:


29

bahamat ve Alan Curry'de haklılar: bunun nedeni kabuğunuzun çıkışını tamponlamasıdır echo. Spesifik olarak, kabuğunuz bash ve writeher satıra bir sistem çağrısı yapar. Bu nedenle, birinci snippet 1000000'lük bir disk dosyasına yazma yapar, ikinci snippet 1000000'lük bir boruya yazma yapar ve sed (büyük ölçüde paralel olarak, eğer birden fazla CPU'nuz varsa) çıkışından dolayı bir disk dosyasına çok daha az sayıda yazma yapar tamponlama.

Strace koşarak neler olduğunu gözlemleyebilirsiniz .

$ strace -f -e write bash -c 'echo -n a\ {1..2}\ c$'\'\\n\'' >file'
write(1, "a 1 c\n", 6)                  = 6
write(1, " a 2 c\n", 7)                 = 7
$ strace -f -e write bash -c 'echo -n a\ {1..2}\ c$'\'\\n\'' | sed "s/^ //" >file'
Process 28052 attached
Process 28053 attached
Process 28051 suspended
[pid 28052] write(1, "a 1 c\n", 6)      = 6
[pid 28052] write(1, " a 2 c\n", 7)     = 7
Process 28051 resumed
Process 28052 detached
Process 28051 suspended
[pid 28053] write(1, "a 1 c\na 2 c\n", 12) = 12
Process 28051 resumed
Process 28053 detached
--- SIGCHLD (Child exited) @ 0 (0) ---

Ksh gibi diğer mermiler echo, multiline olsa bile çıktısını tamponlar , böylece fazla bir fark görmezsiniz.

$ strace -f -e write ksh -c 'echo -n a\ {1..2}\ c$'\'\\n\'' >file'
write(1, "a 1 c\n a 2 c\n", 13)         = 13
$ strace -f -e write ksh -c 'echo -n a\ {1..2}\ c$'\'\\n\'' | sed "s/^ //" >file'
Process 28058 attached
[pid 28058] write(1, "a 1 c\n a 2 c\n", 13) = 13
Process 28058 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
write(1, "a 1 c\na 2 c\n", 12)          = 12

Bash ile benzer zamanlama oranları olsun. Ksh ile ikinci snippet'in daha yavaş çalıştığını görüyorum.

ksh$ time echo -n a\ {1..1000000}\ c$'\n' >file

real    0m1.44s
user    0m1.28s
sys     0m0.06s
ksh$ time echo -n a\ {1..1000000}\ c$'\n' | sed "s/^ //" >file

real    0m2.38s
user    0m1.52s
sys     0m0.14s

Teşekkürler ... Bu son kshörnek beklediğimden çok daha fazlası ...
Peter.O
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.