Bash
Przekierowanie
Szukaj…
Składnia
- polecenie </ ścieżka / do / pliku # Przekieruj standardowe wejście do pliku
- polecenie> / ścieżka / do / pliku # Przekieruj standardowe wyjście do pliku flie
- polecenie file_descriptor> / path / to / file # Przekieruj wyjście deskryptora pliku do pliku
- polecenie> & file_descriptor # Przekieruj wyjście do file_descriptor
- polecenie file_descriptor> & another_file_descriptor # Przekieruj deskryptor pliku na inny_plik_pliku
- polecenie <& file_descriptor # Przekieruj deskryptor pliku na standardowe wejście
- polecenie &> / ścieżka / do / pliku # Przekieruj standardowe wyjście i standardowy błąd do pliku
Parametry
Parametr | Detale |
---|---|
wewnętrzny deskryptor pliku | Liczba całkowita. |
kierunek | Jeden z > , < lub <> |
zewnętrzny deskryptor pliku lub ścieżka | & po nim liczba całkowita deskryptora pliku lub ścieżki. |
Uwagi
Programy konsoli UNIX mają plik wejściowy i dwa pliki wyjściowe (strumienie wejściowe i wyjściowe, a także urządzenia, są traktowane przez system jako pliki). Zazwyczaj są to odpowiednio klawiatura i ekran, ale można przekierować dowolny lub wszystkie z nich pochodzić z - lub przejść do - pliku lub innego programu.
STDIN
jest standardowym wejściem i jest sposobem, w jaki program odbiera dane interaktywne. STDIN
zwykle ma przypisany deskryptor pliku 0.
STDOUT
jest standardowym wyjściem. Cokolwiek jest emitowane na STDOUT
jest uważane za „wynik” programu. STDOUT
zwykle ma przypisany deskryptor pliku 1.
STDERR
to miejsce, w którym wyświetlane są komunikaty o błędach. Zazwyczaj podczas uruchamiania programu z konsoli STDERR
jest wyświetlany na ekranie i jest nie do odróżnienia od STDOUT
. STDERR
zwykle ma przypisany deskryptor pliku 2.
Ważna jest kolejność przekierowań
command > file 2>&1
Przekierowuje zarówno ( STDOUT
i STDERR
) do pliku.
command 2>&1 > file
Przekierowuje tylko STDOUT
, ponieważ deskryptor pliku 2 jest przekierowywany do pliku wskazywanego przez deskryptor pliku 1 (który nie jest jeszcze plikiem file
podczas oceny instrukcji).
Każde polecenie w potoku ma swój własny STDERR
(i STDOUT
), ponieważ każde jest nowym procesem. Może to powodować zaskakujące wyniki, jeśli spodziewane jest, że przekierowanie wpłynie na cały potok. Na przykład to polecenie (zapakowane dla czytelności):
$ python -c 'import sys;print >> sys.stderr, "Python error!"' \
| cut -f1 2>> error.log
wyświetli „Błąd Python!” do konsoli zamiast pliku dziennika. Zamiast tego dołącz błąd do polecenia, które chcesz przechwycić:
$ python -c 'import sys;print >> sys.stderr, "Python error!"' 2>> error.log \
| cut -f1
Przekierowanie standardowego wyjścia
>
przekieruj standardowe wyjście (aka STDOUT
) bieżącego polecenia do pliku lub innego deskryptora.
Te przykłady zapisują dane wyjściowe polecenia ls
w pliku file.txt
ls >file.txt
> file.txt ls
Plik docelowy jest tworzony, jeśli nie istnieje, w przeciwnym razie plik zostanie obcięty.
Domyślnym deskryptorem przekierowania jest standardowe wyjście lub 1
gdy nie określono żadnego. To polecenie jest równoważne z poprzednimi przykładami z wyraźnie wskazanym standardowym wyjściem:
ls 1>file.txt
Uwaga: przekierowanie jest inicjowane przez wykonaną powłokę, a nie przez wykonane polecenie, dlatego odbywa się przed wykonaniem polecenia.
Przekierowanie STDIN
<
czyta z prawego argumentu i zapisuje do lewego argumentu.
Aby zapisać plik do STDIN
, powinniśmy odczytać plik /tmp/a_file
i napisać do STDIN
tj. 0</tmp/a_file
Uwaga: Domyślny wewnętrzny deskryptor pliku to 0
( STDIN
) dla <
$ echo "b" > /tmp/list.txt
$ echo "a" >> /tmp/list.txt
$ echo "c" >> /tmp/list.txt
$ sort < /tmp/list.txt
a
b
c
Przekierowanie zarówno STDOUT, jak i STDERR
Deskryptory plików, takie jak 0
i 1
są wskaźnikami. Zmieniamy, na które deskryptory plików wskazują przekierowanie. >/dev/null
oznacza 1
punkt do /dev/null
.
Najpierw wskazujemy 1
( STDOUT
) na /dev/null
a następnie punkt 2
( STDERR
) na dowolne 1
punkty.
# STDERR is redirect to STDOUT: redirected to /dev/null,
# effectually redirecting both STDERR and STDOUT to /dev/null
echo 'hello' > /dev/null 2>&1
Można to dalej skrócić do następujących:
echo 'hello' &> /dev/null
Jednak ta forma może być niepożądana w produkcji, jeśli chodzi o kompatybilność powłoki, ponieważ jest ona sprzeczna z POSIX, wprowadza niejednoznaczność analizy i powłoki bez tej funkcji źle ją interpretują:
# Actual code
echo 'hello' &> /dev/null
echo 'hello' &> /dev/null 'goodbye'
# Desired behavior
echo 'hello' > /dev/null 2>&1
echo 'hello' 'goodbye' > /dev/null 2>&1
# Actual behavior
echo 'hello' &
echo 'hello' & goodbye > /dev/null
UWAGA: wiadomo, że &>
działa zgodnie z potrzebami zarówno w Bash, jak i Zsh.
Przekierowanie STDERR
2
to STDERR
.
$ echo_to_stderr 2>/dev/null # echos nothing
Definicje:
echo_to_stderr
to polecenie, które zapisuje "stderr"
do STDERR
echo_to_stderr () {
echo stderr >&2
}
$ echo_to_stderr
stderr
Append vs Truncate
Obetnij >
- Utwórz określony plik, jeśli nie istnieje.
- Obetnij (usuń zawartość pliku)
- Napisz do pliku
$ echo "first line" > /tmp/lines
$ echo "second line" > /tmp/lines
$ cat /tmp/lines
second line
Dołącz >>
- Utwórz określony plik, jeśli nie istnieje.
- Dołącz plik (zapis na końcu pliku).
# Overwrite existing file
$ echo "first line" > /tmp/lines
# Append a second line
$ echo "second line" >> /tmp/lines
$ cat /tmp/lines
first line
second line
Wyjaśniono STDIN, STDOUT i STDERR
Polecenia mają jedno wejście (STDIN) i dwa rodzaje wyjść, standardowe wyjście (STDOUT) i standardowy błąd (STDERR).
Na przykład:
STDIN
root@server~# read
Type some text here
Standardowe wejście służy do wprowadzania danych do programu. (Tutaj używamy read
polecenie wbudowane czytać wiersz ze standardowego wejścia).
STDOUT
root@server~# ls file
file
Standardowe wyjście jest zwykle używane do „normalnego” wyjścia z polecenia. Na przykład, ls
wyświetla pliki, więc pliki są wysyłane do STDOUT.
STDERR
root@server~# ls anotherfile
ls: cannot access 'anotherfile': No such file or directory
Standardowy błąd jest (jak sama nazwa wskazuje) używany do komunikatów o błędach. Ponieważ ta wiadomość nie jest listą plików, jest wysyłana do STDERR.
STDIN, STDOUT i STDERR to trzy standardowe strumienie. Są one identyfikowane w powłoce za pomocą numeru, a nie nazwy:
0 = Standardowe w
1 = Wyjście standardowe
2 = Błąd standardowy
Domyślnie STDIN jest podłączony do klawiatury, a zarówno STDOUT, jak i STDERR pojawiają się w terminalu. Możemy jednak przekierować STDOUT lub STDERR na wszystko, czego potrzebujemy. Na przykład, powiedzmy, że potrzebujesz tylko standardowego wyjścia i wszystkie komunikaty o błędach wydrukowane na standardowym błędzie powinny zostać pominięte. Wtedy używamy deskryptorów 1
i 2
.
Przekierowanie STDERR do / dev / null
Biorąc poprzedni przykład,
root@server~# ls anotherfile 2>/dev/null
root@server~#
W takim przypadku, jeśli istnieje jakikolwiek STDERR, zostanie przekierowany do / dev / null (specjalny plik, który ignoruje wszystko, co jest w nim umieszczone), więc nie otrzymasz żadnego wyjścia błędu w powłoce.
Przekierowanie wielu poleceń do tego samego pliku
{
echo "contents of home directory"
ls ~
} > output.txt
Używanie nazwanych potoków
Czasami możesz chcieć wyprowadzić coś przez jeden program i wprowadzić go do innego programu, ale nie możesz użyć standardowego potoku.
ls -l | grep ".log"
Możesz po prostu napisać do pliku tymczasowego:
touch tempFile.txt
ls -l > tempFile.txt
grep ".log" < tempFile.txt
Działa to dobrze w przypadku większości aplikacji, jednak nikt nie będzie wiedział, co robi tempFile
i ktoś może go usunąć, jeśli zawiera on wynik ls -l
w tym katalogu. Tutaj zaczyna się gra nazwana potok:
mkfifo myPipe
ls -l > myPipe
grep ".log" < myPipe
myPipe
jest technicznie plikiem (wszystko jest w Linuksie), więc zróbmy ls -l
w pustym katalogu, w którym właśnie utworzyliśmy potok:
mkdir pipeFolder
cd pipeFolder
mkfifo myPipe
ls -l
Dane wyjściowe to:
prw-r--r-- 1 root root 0 Jul 25 11:20 myPipe
Zwróć uwagę na pierwszy znak w uprawnieniach, jest wymieniony jako potok, a nie plik.
Zróbmy teraz coś fajnego.
Otwórz jeden terminal i zanotuj katalog (lub utwórz taki, aby czyszczenie było łatwe) i utwórz potok.
mkfifo myPipe
Teraz włóżmy coś do fajki.
echo "Hello from the other side" > myPipe
Zauważysz, że się zawiesza, druga strona rury jest nadal zamknięta. Otwórzmy drugą stronę rury i przepuśćmy to.
Otwórz inny terminal i przejdź do katalogu, w którym znajduje się potok (lub jeśli go znasz, dodaj go do potoku):
cat < myPipe
Zauważysz, że po wyjściu hello from the other side
program w pierwszym terminalu kończy się, podobnie jak w drugim terminalu.
Teraz uruchom polecenia w odwrotnej kolejności. Zacznij od cat < myPipe
a następnie cat < myPipe
coś w nim. Nadal działa, ponieważ program będzie czekał, aż coś zostanie wstawione do potoku przed zakończeniem, ponieważ wie, że musi coś dostać.
Nazwane potoki mogą być przydatne do przenoszenia informacji między terminalami lub między programami.
Rury są małe. Po zapełnieniu moduł zapisujący blokuje się, dopóki jakiś czytnik nie odczyta zawartości, dlatego należy albo uruchomić czytnik i moduł zapisujący w różnych terminalach, albo uruchomić jeden lub drugi w tle:
ls -l /tmp > myPipe &
cat < myPipe
Więcej przykładów przy użyciu nazwanych potoków:
Przykład 1 - wszystkie polecenia w tym samym terminalu / tej samej powłoce
$ { ls -l && cat file3; } >mypipe & $ cat <mypipe # Output: Prints ls -l data and then prints file3 contents on screen
Przykład 2 - wszystkie polecenia w tym samym terminalu / tej samej powłoce
$ ls -l >mypipe & $ cat file3 >mypipe & $ cat <mypipe #Output: This prints on screen the contents of mypipe.
Pamiętaj, że najpierw wyświetlana jest zawartość
file3
a następnie danels -l
(konfiguracja LIFO).Przykład 3 - wszystkie polecenia w tym samym terminalu / tej samej powłoce
$ { pipedata=$(<mypipe) && echo "$pipedata"; } & $ ls >mypipe # Output: Prints the output of ls directly on screen
Pamiętaj, że zmienna
$pipedata
nie jest dostępna do użycia w głównym terminalu / głównej powłoce, ponieważ użycie&
wywołuje podpowłokę, a$pipedata
była dostępna tylko w tej podpowłoce.Przykład 4 - wszystkie polecenia w tym samym terminalu / tej samej powłoce
$ export pipedata $ pipedata=$(<mypipe) & $ ls -l *.sh >mypipe $ echo "$pipedata" #Output : Prints correctly the contents of mypipe
$pipedata
to poprawnie wartość zmiennej$pipedata
w głównej powłoce ze względu na deklarację eksportową zmiennej. Główny terminal / główna powłoka nie zawiesza się z powodu wywołania powłoki tła (&
).
Wydrukuj komunikaty o błędach na stderr
Komunikaty o błędach są na ogół zawarte w skrypcie w celu debugowania lub w celu zapewnienia bogatego doświadczenia użytkownika. Po prostu napisz komunikat o błędzie:
cmd || echo 'cmd failed'
może działać w prostych przypadkach, ale nie jest to zwykły sposób. W tym przykładzie, komunikat o błędzie będzie zanieczyszczać rzeczywiste wyjście skryptu przez zmieszanie obu błędów i udane wyjście na stdout
.
Krótko mówiąc, komunikat o błędzie powinien przejść do stderr
nie stdout
. To całkiem proste:
cmd || echo 'cmd failed' >/dev/stderr
Inny przykład:
if cmd; then
echo 'success'
else
echo 'cmd failed' >/dev/stderr
fi
W powyższym przykładzie komunikat o sukcesie zostanie wydrukowany na stdout
a komunikat o błędzie zostanie wydrukowany na stderr
.
Lepszym sposobem wydrukowania komunikatu o błędzie jest zdefiniowanie funkcji:
err(){
echo "E: $*" >>/dev/stderr
}
Teraz, kiedy musisz wydrukować błąd:
err "My error message"
Przekierowanie na adresy sieciowe
Bash traktuje niektóre ścieżki jako specjalne i może wykonywać komunikację sieciową, pisząc do /dev/{udp|tcp}/host/port
. Bash nie może skonfigurować serwera nasłuchującego, ale może zainicjować połączenie, a dla TCP może odczytać przynajmniej wyniki.
Na przykład, aby wysłać proste żądanie internetowe, możesz:
exec 3</dev/tcp/www.google.com/80
printf 'GET / HTTP/1.0\r\n\r\n' >&3
cat <&3
a wyniki domyślnej strony www.google.com
zostaną wydrukowane na standardowe stdout
.
podobnie
printf 'HI\n' >/dev/udp/192.168.1.1/6666
wyśle wiadomość UDP zawierającą HI\n
do słuchacza 192.168.1.1:6666