Zamykanie deskryptora pliku,> & - vs <& -

49

W samouczku bash, który czytam, napisano, że jeśli otworzysz deskryptor pliku do czytania, tj

exec 3< echolist

Musisz to tak zamknąć,

exec 3<&-

Jeśli jednak otworzysz deskryptor pliku do zapisu, musisz go zamknąć w następujący sposób:

exec 3>&-

Jednak kiedy patrzę w Internecie, widzę, jak ludzie otwierają pliki, a następnie zamykają je w ten sposób:

exec 3>&- 

UWAGA: kiedy, zgodnie z samouczkiem, powinni ich używać exec 3<&1.

Więc moje pytanie brzmi: czy wszystkie deskryptory plików mogą zostać zamknięte przez exec n>&-gdzie n jest numerem deskryptora pliku? Niezależnie od tego, czy został otwarty do czytania, pisania, czy obu?

Jason
źródło
21
Jedyną różnicą między >&-i <&-jest domyślny fd, gdy nie jest określony ( >&-jest 1>&-while <&-jest 0<&-). To samo, dla x>&yktórego jest to samo, co x<&yz wyjątkiem sytuacji, gdy xnie jest zapewniony.
Stéphane Chazelas

Odpowiedzi:

48

Możesz zamknąć deskryptor pliku, używając obu <&-i >&-, bashprzeanalizuje dwie składnie jako takie same.

Z pliku y.tab.c w bashkodzie źródłowym:

5385   /* Hack <&- (close stdin) case.  Also <&N- (dup and close). */                
5386   if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND))
5387     return (character);
Cuonglm
źródło
2
Można tego również użyć w <>deskryptorach plików.
CMCDragonkai
1
Nie, nie jest to możliwe, ale jak w 3>&-lub 3<&-wydaje się, aby zamknąć deskryptor.
CMCDragonkai
1
Zamknięcia <>można dokonać na te same sposoby.
CMCDragonkai
1
Nie rozumiem o co ci chodzi. Podaj przykład. /
cuonglm
1
Nie sądzę, że o to mi chodziło. Tyle, że deskryptor zapisu pliku do odczytu można zamknąć również za pomocą 3> & - i 3 <& -.
CMCDragonkai
15

O ile widzę, exec 3>&-i exec 3<&-są takie same i może być używany na dowolnej deskryptora pliku, niezależnie od tego, w jaki sposób została ona otwarta. Zgodnie z sekcjami 2.7.6 i 2.7.5 definicji POSIX języka poleceń poleceń :

2.7.5 Duplikowanie deskryptora pliku wejściowego

Operator przekierowania:

[n] <i słowo

[...FANTASTYCZNA OKAZJA...]

Jeżeli słowo ma wartość „-”, deskryptor pliku n lub standardowe wejście, jeśli n nie jest określone, powinno zostać zamknięte. Próby zamknięcia deskryptora pliku, który nie jest otwarty, nie stanowią błędu. Jeśli słowo zmienia się na coś innego, zachowanie jest nieokreślone.

2.7.6 Duplikowanie deskryptora pliku wyjściowego

Operator przekierowania:

[n]> i słowo

[...FANTASTYCZNA OKAZJA...]

Jeśli słowo zamienia się w „-”, deskryptor pliku n lub standardowe wyjście, jeśli n nie jest określone, jest zamykane. Próby zamknięcia deskryptora pliku, który nie jest otwarty, nie stanowią błędu. Jeśli słowo zmienia się na coś innego, zachowanie jest nieokreślone.

Zauważ, że żadne z nich nie określa niczego, w jaki sposób deskryptor pliku n został otwarty. Jest to zgodne z faktem, że close (2) nie dba o to, jak otworzyłeś plik.

Krótki ciąg następujących czynności:

exec 3< /etc/passwd
exec 4> foo
exec 3<&-
exec 4<&-

kontra to:

exec 3< /etc/passwd
exec 4> foo
exec 3<&-
exec 4>&-

pokazuje, że w obu przypadkach Bash robi dokładnie to samo.

Dwa mało interesujące fakty

Steven D.
źródło
1
Strona podręcznika bash wspomina o zamknięciu, cytując link: Jeśli słowo ma wartość „-”, deskryptor pliku n jest zamknięty.
studog
@studog Dziękujemy za sprawdzenie źródła! Wydaje mi się, że to, co się tutaj wydarzyło, polegało na tym, że szukałem lokalnej strony podręcznika dla Bash 3, a następnie łączyłem się z dokumentacją online, która dotyczyła Bash 4. W starej dokumentacji Bash 3 w opisie [N]>&WORD: git
Steven D
7

Przykład zrozumienia przez cuonglm zamknięcia FD „<>”.

Jest to cytowane w Advanced Bash-Scripting Guide na http://tldp.org/LDP/abs/html/io-redirection.html

[j]<>filename
  #  Open file "filename" for reading and writing,
  #+ and assign file descriptor "j" to it.
  #  If "filename" does not exist, create it.
  #  If file descriptor "j" is not specified, default to fd 0, stdin.
  #
  #  An application of this is writing at a specified place in a file. 
  echo 1234567890 > File    # Write string to "File".
  exec 3<> File             # Open "File" and assign fd 3 to it.
  read -n 4 <&3             # Read only 4 characters.
  echo -n . >&3             # Write a decimal point there.
  exec 3>&-                 # Close fd 3.
  cat File                  # ==> 1234.67890
  #  Random access, by golly.
DMW
źródło