Jak działa plik `cat <>?

42

cat < filewypisuje zawartość pliku na standardowe wyjście.

cat > fileodczytuje stdin aż do wykrycia Ctrl+ Di zapisania tekstu wejściowego do pliku .

cat <> file, przynajmniej w mojej wersji Bash, drukuje zawartość pliku szczęśliwie (bez błędów), ale nie modyfikuje pliku ani nie aktualizuje znacznika czasu modyfikacji.

W jaki sposób standard Bash uzasadnia pozornie ignorowane >w trzecim stwierdzeniu - a co ważniejsze, czy coś robi ?

Qix
źródło

Odpowiedzi:

47

Bash używa <>do utworzenia deskryptora pliku do odczytu i zapisu :

Operator przekierowania

[n]<>word

powoduje, że plik, którego nazwa jest rozwinięciem słowa, jest otwierany zarówno do odczytu, jak i zapisu na deskryptorze pliku n lub na deskryptorze pliku 0, jeśli nie określono n. Jeśli plik nie istnieje, jest tworzony.

cat <> fileotwiera fileodczyt-zapis i wiąże go z deskryptorem 0 (standardowe wejście). Jest to zasadniczo odpowiednik < filekażdego rozsądnie napisanego programu, ponieważ nikt prawdopodobnie nie spróbuje pisać na standardowym wejściu, ale gdyby tak się stało, byłoby to możliwe.

Możesz napisać prosty program w C, aby przetestować to bezpośrednio - write(0, "hello", 6)zapisze hellosię fileza pomocą standardowego wejścia.

<>powinien również działać w dowolnej innej powłoce zgodnej z POSIX z tym samym efektem.

Michael Homer
źródło
1
Pisanie ... na standardowe wejście? ... Czy istnieje jakikolwiek uzasadniony przypadek użycia tego?
Qix
3
Off-hand, nie mogę wymyślić żadnego dobrego. Podanie wyraźnego deskryptora ( 4<>file) jest przydatne i przypuszczam, że 0 jest tak samo dobrym ustawieniem, jak każde, gdy go pominiesz. Czytanie ze standardowego wyjścia nie jest lepsze.
Michael Homer
5
<>jest również przydatny w niektórych systemach (np. Linux) do otwierania nazwanych potoków bez blokowania, dopóki inny proces nie otworzy go do zapisu.
Stéphane Chazelas
1
@Qix: Dobrze pisać (0, „Hasło:”, 10) to dobry sposób na monitowanie o hasło, jeśli zamierzasz pytać o coś w rodzaju tty. Przyzwyczaiłem się widzieć to tylko na stderr, ale bez konkretnego powodu ta sama technika nie działa na stdin.
Joshua
3
@Qix - z uzasadnienia POSIX - <>Operator może być przydatny przy pisaniu aplikacji, która działała z kilkoma terminalami i czasami chciał uruchomić powłokę. Ta powłoka z kolei nie byłaby w stanie uruchamiać aplikacji uruchamianych ze zwykłego terminala sterującego, chyba że mogłaby skorzystać z <>... takiego jak ... pager more, który odczytuje ze standardowego błędu, aby uzyskać swoje polecenia, a więc standardowe wejście i standardowe wyjście oba są dostępne do ich zwykłego użytkowania. cat food | more - >/dev/tty03 2<>/dev/tty03
mikeserv
38

<> fileotwiera plik (domyślnie na deskryptorze pliku 0 (stdin), jak <) w trybie do odczytu i zapisu bez obcinania i tworzenia pliku, jeśli wcześniej nie istniał .

To odpowiada O_RDWR|O_CREATflagom przekazywanym do open()wywołania systemowego. Natomiast <jest O_RDONLYi >jest O_WRONLY|O_CREAT|O_TRUNCi >> O_WRONLY|O_CREAT|O_APPEND.

Zapisywanie standardowego wejścia nie jest często przydatne, ponieważ aplikacje zwykle nie piszą na standardowe wejście. Aplikacje zwykle nie oczekują odczytu i zapisu na deskryptorze pliku, który otrzymują podczas uruchamiania; zwykle czytają ze stdin (lub deskryptora pliku, który sami otwierają) i piszą na stdout lub stderr (lub deskryptorze pliku, który sami otwierają).

<> może mieć swoje zastosowania:

  • Możesz preferować cat <> filewięcej, cat < filejeśli nie chcesz, aby polecenie zakończyło się niepowodzeniem, jeśli filenie istnieje, ale filezamiast tego utworzono puste .
  • Niecięty aspekt <>sprawia, że ​​przydatne jest zastępowanie plików w miejscu. W takim przypadku jednak zazwyczaj nie używasz go w deskryptorze pliku 0:

    printf xxx 1<> file

    zastępuje pierwsze 3 bajty filez xxx.

  • W niektórych systemach, takich jak Linux, <>na nazwanym potoku (FIFO) otwiera nazwany potok bez blokowania (bez oczekiwania na inny proces otwarcia drugiego końca) i zapewnia, że ​​struktura potoku pozostanie przy życiu. Na przykład w:

    mkfifo pipe; sed 's/foo/bar/g' <> pipe

    sedobsługuje przychodzące dane z dowolnej liczby innych procesów zapisujących się na nich i nigdy ich nie widzi eof.

Stéphane Chazelas
źródło
1
Zauważ, że w AT&T ksh93, <>domyślnie jest ustawiony na 1<>(standardowe wyjście) zamiast 0<>(standardowe wejście ). Jest to błąd zgodności z POSIX, który zgłosiłem i zostanie naprawiony w następnej wersji. github.com/att/ast/issues/75 Ale dopóki bieżące wersje ksh93 nie przestaną być używane, musisz podać numer deskryptora pliku, aby używać go <>przenośnie.
Martijn Dekker
@MartijnDekker, wiem, to ja przede wszystkim ci o tym mówiłem ;-). Zauważ, że dotyczy to tylko ksh93t + (gdzie zachowanie się zmieniło) i wyżej.
Stéphane Chazelas
Jakie są (lub były) systemy w przeciwieństwie do Linuksa, w których mkfifo fifo; exec 3<>fifomiałyby się blokować?
Wujek Billy