Dobrym sposobem na sprawdzenie różnicy między nimi jest przeprowadzenie małego eksperymentu w wierszu poleceń. Pomimo wizualnego podobieństwa w użyciu <
postaci, robi ona coś zupełnie innego niż przekierowanie lub potok.
Użyjmy date
polecenia do testowania.
$ date | cat
Thu Jul 21 12:39:18 EEST 2011
Jest to bezcelowy przykład, ale pokazuje, że cat
zaakceptował wyjście date
STDIN i wypluł je z powrotem. Te same wyniki można osiągnąć przez podstawienie procesu:
$ cat <(date)
Thu Jul 21 12:40:53 EEST 2011
Jednak to, co stało się za kulisami, było inne. Zamiast otrzymać strumień STDIN, cat
faktycznie przekazano nazwę pliku, który musiał otworzyć i odczytać. Możesz zobaczyć ten krok, używając echo
zamiast cat
.
$ echo <(date)
/proc/self/fd/11
Gdy kot otrzymał nazwę pliku, odczytał dla nas zawartość pliku. Z drugiej strony echo po prostu pokazało nam nazwę pliku, który został przekazany. Ta różnica staje się bardziej oczywista, jeśli dodasz więcej podstawień:
$ cat <(date) <(date) <(date)
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011
$ echo <(date) <(date) <(date)
/proc/self/fd/11 /proc/self/fd/12 /proc/self/fd/13
Możliwe jest połączenie podstawienia procesu (który generuje plik) i przekierowania wejściowego (które łączy plik ze STDIN):
$ cat < <(date)
Thu Jul 21 12:46:22 EEST 2011
Wygląda prawie tak samo, ale tym razem kotowi przekazano strumień STDIN zamiast nazwy pliku. Możesz to zobaczyć, wypróbowując to za pomocą echa:
$ echo < <(date)
<blank>
Ponieważ echo nie odczytuje STDIN i nie przekazano żadnego argumentu, nic nie otrzymujemy.
Potoki i dane wejściowe przekierowują zawartość wtykową do strumienia STDIN. Podstawianie procesów uruchamia polecenia, zapisuje ich dane wyjściowe w specjalnym pliku tymczasowym, a następnie przekazuje tę nazwę pliku zamiast polecenia. Każde używane polecenie traktuje to jako nazwę pliku. Zauważ, że utworzony plik nie jest zwykłym plikiem, ale nazwanym potokiem, który jest automatycznie usuwany, gdy nie jest już potrzebny.
[[ -p <(date) ]] && echo true
. Powoduje to,true
gdy uruchamiam go z bash 4.4 lub 3.2.Przypuszczam, że mówisz o
bash
jakiejś innej zaawansowanej powłoce, ponieważ powłoka posix nie ma substytucji procesu .bash
raporty strony podręcznika:Innymi słowy i z praktycznego punktu widzenia możesz użyć wyrażenia takiego jak poniżej
jako nazwa pliku dla innych poleceń wymagających pliku jako parametru. Lub możesz użyć przekierowania dla takiego pliku:
Wracając do twojego pytania, wydaje mi się, że podstawianie procesów i rury nie mają ze sobą wiele wspólnego.
Jeśli chcesz przesyłać sekwencyjnie dane wyjściowe wielu poleceń, możesz użyć jednej z następujących form:
ale możesz również użyć przekierowania podczas zastępowania procesu
na koniec, jeśli
command3
zaakceptuje parametr pliku (w zamian stdin)źródło
Oto trzy rzeczy, które możesz zrobić z podstawieniem procesu, które w przeciwnym razie są niemożliwe.
Wiele wejść procesowych
Po prostu nie da się tego zrobić za pomocą rur.
Zachowanie STDIN
Powiedz, że masz następujące elementy:
I chcesz uruchomić go bezpośrednio. Następujące zawodzi żałośnie. Bash już używa STDIN do odczytu skryptu, więc inne dane wejściowe są niemożliwe.
Ale ten sposób działa idealnie.
Zastąpienie procesu wychodzącego
Należy również pamiętać, że podstawianie procesów działa również w drugą stronę. Możesz więc zrobić coś takiego:
To trochę skomplikowany przykład, ale wysyła stdout do
/dev/null
, jednocześnie przesyłając stderr do skryptu sed, aby wyodrębnić nazwy plików, dla których wyświetlony został błąd „Odmowa zezwolenia”, a następnie wysyła wyniki THOSE do pliku.Należy pamiętać, że pierwsze polecenie i stdout przekierowanie jest w nawiasie ( podpowłoce ), tak, że tylko wynik tego polecenia zostanie wysłana do
/dev/null
i nie bałagan z resztą linii.źródło
diff
przykładzie warto dbać o przypadku, kiedycd
może zakończyć się niepowodzeniem:diff <(cd /foo/bar/ && ls) <(cd /foo/baz && ls)
.Jeśli polecenie pobiera listę plików jako argumenty i przetwarza te pliki jako dane wejściowe (lub wyjściowe, ale niezbyt często), każdy z tych plików może być nazwanym potokiem lub pseudo-plikiem / dev / fd zapewniany w sposób przezroczysty przez substytucję procesu:
Spowoduje to „potokowanie” danych wyjściowych trzech poleceń do sortowania, ponieważ sortowanie może zająć listę plików wejściowych w wierszu polecenia.
źródło
<()
, podobnie jak wiele zaawansowanych funkcji powłoki, był pierwotnie funkcją ksh i został przyjęty przez bash i zsh.psub
jest szczególnie cechą ryb, nie ma nic wspólnego z POSIX.Należy zauważyć, że podstawienie procesu nie ogranicza się do formy
<(command)
, która wykorzystuje dane wyjściowecommand
jako plik. Może być również w formie,>(command)
która podaje plik jako dane wejściowecommand
. Jest to również wspomniane w cytacie podręcznika bash w odpowiedzi na @ enzotib.W
date | cat
powyższym przykładzie polecenie, które korzysta z substytucji procesu w>(command)
celu uzyskania tego samego efektu, brzmiałoby:Pamiętaj, że
>
wcześniejsze>(cat)
jest konieczne. Można to ponownie wyraźnie zilustrować za pomocąecho
odpowiedzi @ Caleb.Tak więc, bez dodatkowych
>
,date >(cat)
byłoby to to samo,date /dev/fd/63
co wypisze wiadomość do stderr.Załóżmy, że masz program, który bierze nazwy plików tylko jako parametry i nie przetwarza
stdin
lubstdout
. Wykorzystam uproszczony skrypt,psub.sh
aby to zilustrować. Zawartośćpsub.sh
jestZasadniczo sprawdza, czy oba jego argumenty są plikami (niekoniecznie zwykłymi plikami), a jeśli tak jest, napisz pierwsze pole każdej linii
"$1"
do"$2"
użycia awk. Następnie polecenie, które łączy wszystkie wspomniane do tej pory, to:To zostanie wydrukowane
i jest równoważne z
ale następujące działania nie będą działać i musimy tutaj zastosować podstawianie procesów,
lub jego odpowiednik
Jeśli
./psub.sh
odczytuje równieżstdin
poza tym, co wspomniano powyżej, to taka równoważna forma nie istnieje, aw takim przypadku nie możemy nic użyć zamiast zastępowania procesu (oczywiście możesz również użyć nazwanego pliku potoku lub pliku tymczasowego, ale to inny fabuła).źródło