stdout
jednego programu ze standardowym wejściem stdin
drugiego. Standardowe wyjście błędów stderr
domyślnie nie trafia do potoku, co można zaobserwować w niektórych programach robiąc program --help | more
i klnąc, że 3 strony pomocy przeleciały nam przez ekran niepowstrzymane. ;)Istnieje kilka narzędzi, które można wykorzystać do zmierzenia i wizualizacji wolumenu danych płynących potokiem, a nawet do ograniczenia natężenia:
Są one często dostępne w standardowym repozytorium pakietów oprogramowania.
Przy ich pomocy można "zobaczyć", jak szybko przetwarzane są dane np. podczas obliczania sumy kontrolnej pliku. Można też zobaczyć na bieżąco, jak dane na wejściu kompresują się po przejściu przez archiwizer. Można wreszcie spowolnić przesyłanie danych, aby zmniejszyć wykorzystanie zasobów systemu (np. sieci, jeśli w potoku uczestniczy program sieciowy) lub... po prostu wyświetlać animację w ASCII. ;)
Przykłady? Dla testu wyślę do potoku dane pobrane
dd
z generatora liczb pseudolosowych urandom
(o nieco niższej jakości, ale za to nieblokującego po wyczerpaniu entropii). Następnie spróbuję ograniczyć prędkość, z jaką pobieram pseudolosowe dane.
$ dd if=/dev/urandom bs=1M count=10 | pipebench > /dev/null
10+0 records in 9.37 MB 6.25 MB/second (Sun May 23 13:24:40 2010)
10+0 records out
10485760 bytes (10 MB) copied, 1,52052 s, 6,9 MB/s
Summary:
Piped 10.00 MB in 00h00m01.52s: 6.55 MB/second
$ dd if=/dev/urandom bs=512k count=1 | cpipe -vr -vt -vw -ngr -s 100 > /dev/null
in: 96.327ms at 1.3MB/s ( 1.3MB/s avg) 128.0kB
out: 0.002ms at 61.0GB/s ( 61.0GB/s avg) 128.0kB
thru: 1256.614ms at 101.9kB/s ( 101.9kB/s avg) 128.0kB
in: 0.266ms at 469.9MB/s ( 2.6MB/s avg) 256.0kB
out: 0.002ms at 61.0GB/s ( 61.0GB/s avg) 256.0kB
thru: 1257.576ms at 101.8kB/s ( 101.8kB/s avg) 256.0kB
in: 0.220ms at 568.2MB/s ( 3.9MB/s avg) 384.0kB
out: 0.003ms at 40.7GB/s ( 52.3GB/s avg) 384.0kB
thru: 1260.403ms at 101.6kB/s ( 101.7kB/s avg) 384.0kB
1+0 records in
1+0 records out
524288 bytes (524 kB) copied, 3,77087 s, 139 kB/s
in: 0.985ms at 126.9MB/s ( 5.1MB/s avg) 512.0kB
out: 0.003ms at 40.7GB/s ( 48.8GB/s avg) 512.0kB
thru: 1262.864ms at 101.4kB/s ( 101.6kB/s avg) 512.0kB
in: 0.005ms at 0B/s ( 5.1MB/s avg) 512.0kB (bsize=0)
out: 0.001ms at 0B/s ( 44.4GB/s avg) 512.0kB
thru: 0.055ms at 0B/s ( 101.6kB/s avg) 512.0kB
$ dd if=/dev/urandom bs=1M count=1 | pv -L 100K > /dev/null
90kB 0:00:03 [ 101kB/s] [ <=> ]
Potoki mogą też być nazwane - widnieją wówczas w systemie plików jako plik typu FIFO i możemy do nich zapisywać dane jak do każdego innego pliku. Różnica jest taka, że zapis będzie blokujący tzn. będzie czekał, aż "z drugiej strony" do potoku nie podłączy się konsument.
$ mkfifo pipe1 pipe2
$ ls -las pipe*
0 prw-r--r-- 1 blog blog 0 maj 24 22:33 pipe1
0 prw-r--r-- 1 blog blog 0 maj 24 22:33 pipe2
$ echo "zapis do potoku w tle" > pipe1 &
[1] 2834
$ cat pipe1
zapis do potoku w tle
[1]+ Done echo "zapis do potoku w tle" > pipe1
$ cat pipe1 &
[1] 2836
$ echo "zapis do potoku czytanego w tle" > pipe1
zapis do potoku czytanego w tle
[1]+ Done cat pipe1
Tak uzbrojeni możemy sięgnąć po narzędzie do rozszczepiania potoku, czyli
tee
. tee
przepuszcza swoje wejście na wyjście, ale robi kopię danych i wysyła do wskazanego pliku.
$ echo DANE TESTOWE | tee kopia-strumienia
DANE TESTOWE
$ cat kopia-strumienia
DANE TESTOWE
Przy pomocy
tee
można np. kompresować plik i jednocześnie liczyć sobie sumę kontrolną pliku wynikowego "w trakcie".W szczególności plik podany
tee
może być potokiem nazwanym, czyli strumień trafi do 2 potoków jednocześnie.
$ echo DANE TESTOWE | tee pipe1 | sed s/DANE/POTOCZYSCIE/ &
[1] 2932
$ cat pipe1
POTOCZYSCIE TESTOWE
DANE TESTOWE
[1]+ Done echo DANE TESTOWE | tee pipe1 | sed s/DANE/POTOCZYSCIE/
Świetnie, a czy da się np. zamienić miejscami strumień
stdout
i stderr
? Albo czy da się otworzyć więcej niż te dwa standardowe strumienie? Oczywiście. :)Dla przypomnienia: proces ma listę otwartych deskryptorów. Standardowo mamy otwarte:
- deskryptor 0, czyli stdin
- deskryptor 1, czyli stdout
- deskryptor 2, czyli stderr
bash
, robimy to np. następująco (do czytania):
$ echo DANE > myfile
$ cat <&3
DANE
No to zamieńmy miejscami
stdout
i stderr
:
$ echo DANE | grep -v DANE
$ echo DANE 3>&1 1>&2 2>&3 | grep -v DANE
DANE
A jeśli naotwieramy więcej deskryptorów, to czy da się jakoś operować więcej niż na parze z nich? Z pomocą przychodzi narzędzie
multitee
.
$ echo DANE1>plik1
$ echo DANE2>plik2
$ echo DANE3>plik3
$ exec 3wyjscie1
$ exec 7>wyjscie2
$ exec 8>>wyjscie3
$ echo WEJSCIOWE | multitee 0:6,7,8 3:8 4:8 5:6
$ cat wyjscie1
DANE3
WEJSCIOWE
$ cat wyjscie2
WEJSCIOWE
$ cat wyjscie3
DANE2
DANE1
WEJSCIOWE
Na koniec pozostaje pozamykać deskryptory:
$ exec 3>&-
itd.
Brak komentarzy:
Prześlij komentarz