Process substitution

Process substitution, czyli w wolnym tłumaczeniu “podstawienie procesu” to rodzaj komunikacji międzyprocesowej, który umożliwia przekierowanie wyjścia jednego programu na wejście innego. Odbywa się to bardzo podobnie jak utworzenie nienazwanego potoku przy pomocy operatora pałki |, z tą różnicą, że na wejście jednego programu mogą zostać przekierowane wyjścia z wielu programów.

Process substitution zapisywany jest poprzez użycie operatora <(). Technika ta umożliwia przekazanie wyjść programów w miejsce, gdzie inny program normalnie otrzymuje listę argumentów będących jego plikami wejściowymi. Przykładowo poniższe wywołanie spowoduje porównanie zawartości dwóch katalogów:

$ diff <(ls dir1) <(ls dir2)

Oczywiście wywołania mogą być łączone. Poniżej nieco bezsensowny przykład otwarcia w Vimie przegrepowanej skrzynki odbiorczej:

$ vim <(grep -e "From" <(head -n100 ~/mbox))

Działa to również w drugą stronę. Jeśli możemy podać komendzie plik wyjściowy (czyli taki, do którego będzie pisała), to przy pomocy operatora >() możemy w to miejsce podstawić wejście innego programu. Przykładowo, poniższe wywołanie spowoduje utworzenie dwóch plików zawierających listy plików z rozszerzeniem jpg i png. Samo tworzenie plików zawdzięczamy, przekierowaniu wyjścia z grepa do pliku, natomiast oba grepy otrzymają to samo wyjście z wywołania komendy ls:

$ ls | tee >(grep png > png_files) >(grep jpg > jpg_files)

Interesującym użyciem jest możliwość przekazania standardowego wyjścia do programu, który normalnie nie jest w stanie go obsłużyć. Aby to sprezentować, ponownie posłużę się głupim przykładem. Jeśli nasz zarówno nasz terminal, jak i grep obsługują kolory, powinno to spowodować podświetlenie litery “b”:

$ echo "abc" > >(grep -e "b" <(cat))

Podstawianie procesów jest nie tylko wygodne, ale i efektywne, gdyż na dysku nie są zapisywane żadne dane tymczasowe (chociaż czas dostępu do dysku w czasach dysków SSD powoli traci na znaczeniu). Co więcej, jeśli to tylko możliwe, komendy będą wywoływane równolegle.

Przy wszystkich dobrodziejstwach zaprezentowanych technik należy jednak pamiętać o ich ograniczeniach. Przede wszystkim z wywoływanych w ten sposób komend nie jesteśmy w stanie pobrać kodu wyjścia, a więc nie jesteśmy w stanie w prosty sposób dowiedzieć się o powodzeniu (lub nie) komendy. Z drugiej strony, ponieważ shell utworzy albo plik w /proc/self/fd, albo nazwany potok, nie można zmienić pozycji w takim “sztucznym pliku”, co może skutkować tym, że nie wszystkie programy będą z nim dobrze współpracować.