Większość poleceń ma jeden kanał wejściowy (standardowe wejście, deskryptor pliku 0) i jeden kanał wyjściowy (standardowe wyjście, deskryptor pliku 1) lub działają na kilku plikach, które same otwierają (więc podajesz im nazwę pliku). (Jest to dodatek do standardowego błędu (fd 2), który zwykle filtruje całą drogę do użytkownika.) Czasami jednak wygodne jest posiadanie polecenia, które działa jak filtr z kilku źródeł lub z kilku celów. Na przykład, oto prosty skrypt, który oddziela nieparzyste linie w pliku od parzystych
while IFS= read -r line; do
printf '%s\n' "$line"
if IFS= read -r line; then printf '%s\n' "$line" >&3; fi
done >odd.txt 3>even.txt
Załóżmy teraz, że chcesz zastosować inny filtr do linii o liczbach nieparzystych i do linii o parzystych numerach (ale nie odkładaj ich razem, to byłby inny problem, niewykonalny w stosunku do powłoki). W powłoce można tylko potokować standardowe wyjście polecenia do innego polecenia; aby potokować inny deskryptor pliku, musisz najpierw przekierować go do fd 1.
{ while … done | odd-filter >filtered-odd.txt; } 3>&1 | even-filter >filtered-even.txt
Innym, prostszym przypadkiem użycia jest filtrowanie wyniku błędu polecenia .
exec M>&N
przekierowuje deskryptor pliku na inny na pozostałą część skryptu (lub do momentu, gdy inne takie polecenie ponownie nie zmieni deskryptorów plików). Funkcjonalność między exec M>&N
i występuje w pewnym stopniu somecommand M>&N
. exec
Forma jest bardziej wydajny w tym, że nie musi być zagnieżdżone:
exec 8<&0 9>&1
exec >output12
command1
exec <input23
command2
exec >&9
command3
exec <&8
Inne przykłady, które mogą być interesujące:
I jeszcze więcej przykładów:
PS To zaskakujące pytanie autora najpopularniejszego postu na stronie, który korzysta z przekierowania przez fd 3 !
while IFS= read -r line;
? Z mojego punktu widzenia IFS nie ma tu żadnego wpływu, ponieważ przypisujesz wartość tylko jednej zmiennej ( linii ). Zobacz to pytanie.IFS
robi różnicę, nawet jeśli czytasz jedną zmienną (aby zachować wiodące białe znaki).sed -ne 'w odd.txt' -e 'n;w even.txt'
?Oto przykład użycia dodatkowych FD jako kontroli chattiness skryptu bash:
źródło
W kontekście nazwanych potoków (fifos) użycie dodatkowego deskryptora pliku może umożliwić zachowanie nieblokującego potoku.
Zobacz: Nazwane zamknięcie potoku w skrypcie?
źródło
Dodatkowy deskryptor pliku jest przydatny, gdy chcesz złapać standardowe wyjście w zmiennej, ale nadal chcesz zapisać na ekranie, na przykład w interfejsie użytkownika skryptu bash
źródło
Oto kolejny scenariusz, w którym użycie dodatkowego deskryptora pliku wydaje się odpowiednie (w Bash):
Zabezpieczenie hasła skryptu powłoki parametrami wiersza polecenia
źródło
Przykład: użycie flocka do wymuszenia szeregowego działania skryptów z blokadami plików
Jednym z przykładów jest użycie blokady plików, aby zmusić skrypty do szeregowego uruchamiania w całym systemie. Jest to przydatne, jeśli nie chcesz, aby dwa skrypty tego samego rodzaju działały na tych samych plikach. W przeciwnym razie oba skrypty zakłócałyby się wzajemnie i powodowałyby uszkodzenie danych.
Użyj stada funkcjonalnie, definiując blokadę i odblokowanie
Możesz także zawinąć tę logikę blokowania / odblokowywania w funkcje wielokrotnego użytku. Następująca
trap
wbudowana powłoka automatycznie zwolni blokadę pliku, gdy skrypt zakończy działanie (błąd lub sukces).trap
pomaga wyczyścić blokady plików. Ścieżka/tmp/file.lock
powinna być ścieżką zakodowaną na stałe, aby wiele skryptów mogło próbować się na niej zablokować.Powyższa
unlock
logika polega na usunięciu pliku przed zwolnieniem blokady. W ten sposób czyści plik blokady. Ponieważ plik został usunięty, inna instancja tego programu może uzyskać blokadę pliku.Wykorzystanie funkcji blokowania i odblokowywania w skryptach
Możesz użyć go w swoich skryptach, jak w poniższym przykładzie.
Jeśli chcesz, aby Twój kod czekał, aż będzie mógł się zablokować, możesz dostosować skrypt w następujący sposób:
źródło
Jako konkretny przykład właśnie napisałem skrypt, który potrzebuje informacji o taktowaniu z podkomendy. Użycie dodatkowego deskryptora pliku pozwoliło mi przechwycić
time
stderr polecenia bez przerywania stdout lub stderr podkomendy.To robi to punkt
ls
stderr do fd 3, punkt fd 3 do stderr skryptu i punkttime
stderr do pliku. Po uruchomieniu skryptu jego stdout i stderr są takie same jak polecenia podkomendy, które można przekierować jak zwykle. Tylkotime
dane wyjściowe są przekierowywane do pliku.źródło