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
4.0

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 >

  1. Utwórz określony plik, jeśli nie istnieje.
  2. Obetnij (usuń zawartość pliku)
  3. Napisz do pliku
$ echo "first line" > /tmp/lines
$ echo "second line" > /tmp/lines

$ cat /tmp/lines
second line

Dołącz >>

  1. Utwórz określony plik, jeśli nie istnieje.
  2. 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 dane ls -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

2.04

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



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow