Czy 3> i 1 oznacza 4> i 3 5> i 3 itd.?

31

Oczekiwałbym

echo foo | tee /proc/self/fd/{3..6} 3>&1

nie udać się z błędami takimi jak / proc / self / fd / 4: Nie ma takiego pliku lub katalogu itp., ale ku mojemu zaskoczeniu, wyświetla

foo
foo
foo
foo
foo

To tak, jakby 3>&1wszystkie poniższe deskryptory zostały przekierowane na standardowe wyjście, z wyjątkiem tego, że nie działa, jeśli zmienię 3na coś innego, na przykład

$ echo foo | tee /proc/self/fd/{3..6} 4>&1
tee: /proc/self/fd/3: No such file or directory
tee: /proc/self/fd/5: No such file or directory
tee: /proc/self/fd/6: No such file or directory
foo
foo
$ echo foo | tee /proc/self/fd/{4..6} 4>&1
tee: /proc/self/fd/5: No such file or directory
tee: /proc/self/fd/6: No such file or directory
foo
foo

Czy istnieje wyjaśnienie tego zachowania?

oguz ismail
źródło

Odpowiedzi:

31

strace pokazuje następującą sekwencję wywołań systemowych:

$ strace -o strace.log tee /proc/self/fd/{3..6} 3>&1
...
$ cat strace.log
...
openat(AT_FDCWD, "/proc/self/fd/3", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
openat(AT_FDCWD, "/proc/self/fd/4", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 5
openat(AT_FDCWD, "/proc/self/fd/5", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
openat(AT_FDCWD, "/proc/self/fd/6", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 7
...

Pierwszy wiersz otwiera się /proc/self/fd/3i przypisuje mu następny dostępny numer fd, 4. /proc/self/fd/3jest specjalną ścieżką. Otwarcie ma efekt podobny do kopiowania fd 3: fd 4 punkty w to samo miejsce co fd 3, tty.

To samo dzieje się z każdym kolejnym openat()połączeniem. Gdy kurz osiada, wszystkie 4, 5, 6 i 7 są duplikatami fd 3.

  • 1 → tty
  • 3 → tty
  • 4 → tty
  • 5 → tty
  • 6 → tty
  • 7 → tty

Pamiętaj, że 3>&1przekierowanie nie jest ważne. Ważne jest to, że prosimy tee o otwarcie /proc/self/fd/Ntam, gdzie N jest już w użyciu. Powinniśmy uzyskać ten sam wynik, jeśli się go pozbędziemy 3>&1i /proc/self/fd/2zamiast tego zaczniemy od początku . Zobaczmy:

$ echo foo | tee /proc/self/fd/{2..6}
foo
foo
foo
foo
foo
foo

Potwierdzony! Ten sam wynik.

Możemy również powtarzać ten sam numer fd w kółko. Ten sam wynik osiągamy, gdy nacisniemy fd 6. Zanim osiągnie ostatni, otworzył wystarczająco dużo deskryptorów, aby umożliwić skok do 6.

$ echo foo | tee /proc/self/fd/{2,2,2,2,6}
foo
foo
foo
foo
foo
foo
John Kugelman
źródło